Compare commits

..
Author SHA1 Message Date
Madalina Raicu 407a03353d Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-08-03 10:13:29 +01:00
Joe Tsang 6686755763 chore(governance): fix failing tests from nightly run (#4453) 2023-08-03 10:01:00 +01:00
Joe Tsang 79cf8163be chore(governance): add e2e test for successor market (#4471) 2023-08-03 09:54:51 +01:00
Matthew Russell 1688e26f4b feat(trading): add fairground texture background to logo (#4474) 2023-08-03 09:28:01 +01:00
Art 5e101a8eaf feat(trading): deposit page (#4472) 2023-08-02 19:06:49 +02:00
Matthew Russell 65071f57d0 fix(trading,governance): eager connection for browser wallet (#4444) 2023-08-02 17:16:09 +01:00
daro-maj b87c981a90 test(trading): fix for key-to-key test (#4469) 2023-08-02 18:11:31 +02:00
Joe TsangandMatthew Russell b509e5b347 test(explorer): e2e proposal test (#4379)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-08-02 16:37:55 +01:00
Maciek bb9fce4831 feat(trading): 4322 get started steps (#4440) 2023-08-02 15:34:04 +00:00
Madalina Raicu 768f3c3ed1 fix: remove mock 2023-08-02 16:26:04 +01:00
Madalina Raicu 4add2d1c8c fix: update order view dialog on market click 2023-08-02 16:21:39 +01:00
Madalina Raicu 24953b45c6 fix: update order view and tests 2023-08-02 16:14:07 +01:00
Matthew Russell 918825aca8 chore: adjust spacing and text size of long/short type selectors 2023-08-02 15:36:39 +01:00
Matthew Russell 74bf183fad feat(trading): 3114 pane context (#4442) 2023-08-02 15:29:41 +01:00
m.ray 674baa1ee3 fix(trading): iceberg order fills (#4460) 2023-08-02 16:55:49 +03:00
Matthew Russell d18a0c7e15 fix(trading): lp table forward ref breaking resize grid (#4447) 2023-08-02 13:59:05 +01:00
m.ray 76a6005b77 fix(trading): replace all markets with open markets (#4452) 2023-08-02 13:58:26 +01:00
JonRay15andMatthew Russell 79414614c2 chore(trading,governance,explorer): fix issue template (#4459)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-08-02 12:52:51 +01:00
Madalina Raicu a98d6083d7 fix: add order view dialog test 2023-08-02 12:39:32 +01:00
Madalina Raicu 4c87b82da3 fix: add order view dialog test 2023-08-02 12:35:04 +01:00
Madalina Raicu e73c7cf173 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-08-02 11:57:49 +01:00
m.ray fde49e5446 fix(trading): order stopped misleading message (#4455) 2023-08-02 11:52:07 +01:00
JonRay15andMatthew Russell 45283161aa chore: create feature-epic issue template (#4456)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-08-02 11:48:23 +01:00
Bartłomiej GłowniaandDariusz Majcherczyk 375d447fa8 feat(trading): add stop orders table and form (#4265)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-08-02 11:28:33 +01:00
Mikołaj Młodzikowski 1dd97a2bce feat(ci): add develop docker image (#4458) 2023-08-02 10:58:17 +02:00
Madalina Raicu 1cc483ec6c fix: build issues order-spec 2023-08-01 18:26:22 +01:00
Madalina Raicu 21275659f1 fix: remove explorer link - can't link order 2023-08-01 18:10:34 +01:00
Madalina Raicu fa27c6d6f1 fix: update types for stagnet1 2023-08-01 18:05:29 +01:00
Madalina Raicu 5768aa1032 feat(trading): update order details 2023-08-01 18:00:44 +01:00
Edd d4a1a9b193 fix(explorer): add tests and fix transactions url generation (#4454) 2023-08-01 16:35:40 +01:00
Madalina Raicu ffe41e25f4 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-08-01 15:49:25 +01:00
Edd 376c5241a8 feat(explorer): improve transaction pagination (#4435) 2023-08-01 14:41:16 +00:00
Madalina Raicu e50b894f0b Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-08-01 10:47:05 +01:00
Ciaran McGhie 8e6d8517cf feat(ui-toolkit,tailwindcss-config): healthbar auction level indicator (#4406) 2023-08-01 09:44:03 +01:00
Matthew Russell 5f9ec222c1 feat(trading): navigation (#4375) 2023-07-31 17:08:55 +01:00
Edd 8954c41c0a fix(governance): remove incorrect individual reward percentage (#4443) 2023-07-31 15:23:52 +00:00
Madalina Raicu 38134e3036 fix: order data provider 2023-07-18 21:20:46 +02:00
Madalina Raicu 9333061349 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-07-18 21:20:07 +02:00
Madalina Raicu 7acdad8a6d Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-07-17 14:33:03 +02:00
Madalina Raicu 57ac2150fe Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/order-details 2023-07-11 08:58:26 +01:00
Madalina Raicu ee21137ed8 feat(trading): view order details 2023-07-10 18:06:07 +01:00
Madalina Raicu 9a8e4b2526 fix: order type cast removed 2023-07-10 14:39:57 +01:00
Madalina Raicu 96db36fa67 fix: add extra field 2023-07-07 22:35:31 +03:00
Madalina Raicu 381c1d34c8 fix: order fields update 2023-07-07 18:49:39 +03:00
Madalina Raicu cb797e5b3f fix: add typename 2023-07-07 18:19:07 +03:00
Madalina Raicu 6366f5d7de chore: remove remaining from tx res 2023-07-07 13:04:26 +03:00
Madalina Raicu 7fe867756c Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/view-iceberg-orders 2023-07-06 15:16:27 +03:00
Madalina Raicu dc4a7e63b5 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/view-iceberg-orders 2023-07-06 11:17:50 +03:00
Madalina Raicu 5ef0969dcb fix: update types 2023-07-06 00:32:28 +03:00
Madalina Raicu 13d13bd930 Merge branch 'develop' of github.com:vegaprotocol/frontend-monorepo into feat/view-iceberg-orders 2023-07-05 00:18:48 +03:00
Madalina Raicu c3b95357dc fix: transfer type mappings 2023-07-04 17:59:59 +03:00
Madalina Raicu 1d74fd8311 Merge branch 'feat/view-iceberg-orders' of github.com:vegaprotocol/frontend-monorepo into feat/view-iceberg-orders 2023-07-04 17:58:21 +03:00
Madalina Raicu 981212bd64 fix: proposal type mappings 2023-07-04 17:58:07 +03:00
Madalina Raicu 54e6aadfa3 fix: account type holding 2023-07-04 17:49:20 +03:00
Madalina Raicu be86d91249 fix: remove log 2023-07-04 17:48:17 +03:00
Madalina Raicu 800b884ad9 fix: revert orders data provider changes 2023-06-28 16:41:12 +03:00
Madalina Raicu 32c8a926a5 feat(trading): view iceberg orders 2023-06-28 15:47:51 +03:00
242 changed files with 6811 additions and 2648 deletions
+2 -1
View File
@@ -51,7 +51,8 @@
"ul": ["list"],
"ol": ["list"]
}
]
],
"no-console": ["error", { "allow": ["warn", "error"] }]
}
},
{
+29
View File
@@ -0,0 +1,29 @@
---
name: Feature Epic
about:
A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
title: 'Epic: '
labels: feature-epic
---
## Core Feature
<Name>
## Tasks
- [ ] Define high level requirements
- [ ] Create basic mockups
- [ ] Update "API Requirements" in core spec
- [ ] Update "User-Interface Spec" in relevant front end repo
- [ ] Create detailed user stories using normal template
## High Level Requirements
## Basic Mockups
## Link to API Requirements in Core spec
## Link to User Interface Specs
## Linked User Stories
+9 -3
View File
@@ -29,6 +29,12 @@ jobs:
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
echo IS_S3_RELEASE=false >> $GITHUB_ENV
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
- name: Is dev image
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
run: |
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
- name: Is PR
if: ${{ github.event_name == 'pull_request' }}
@@ -75,7 +81,7 @@ jobs:
- name: Log in to the Container registry (docker hub)
uses: docker/login-action@v2
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -173,7 +179,7 @@ jobs:
uses: docker/build-push-action@v3
continue-on-error: true
id: dockerhub-push
if: ${{ env.IS_IPFS_RELEASE == 'true' }}
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
with:
context: .
file: docker/node-outside-docker.Dockerfile
@@ -183,7 +189,7 @@ jobs:
ENV_NAME=${{ env.ENV_NAME }}
tags: |
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}
- name: Publish dist as docker image (ghcr - retry)
uses: docker/build-push-action@v3
@@ -0,0 +1,46 @@
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('/');
cy.createMarket();
});
it('Able to view proposal', function () {
cy.navigate_to('governanceProposals');
cy.getByTestId(proposalHeading).should('be.visible');
// get first proposal in list
cy.get('[row-index="0"]').within(() => {
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
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.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();
});
cy.getByTestId('dialog-title').should('have.text', proposalTitle);
cy.get('.language-json').should('exist');
});
it('Proposal page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.navigate_to('governanceProposals', true);
cy.getByTestId(proposalHeading).should('be.visible');
cy.get('[row-index="0"]').within(() => {
cy.get_element_by_col_id('title').should('have.text', proposalTitle);
});
});
});
});
@@ -10,7 +10,6 @@ import {
DropdownMenuTrigger,
DropdownMenuSubContent,
Icon,
Button,
} from '@vegaprotocol/ui-toolkit';
import type { Dispatch, SetStateAction } from 'react';
import { FilterLabel } from './tx-filter-label';
@@ -100,15 +99,13 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
<DropdownMenu
modal={false}
trigger={
<DropdownMenuTrigger className="ml-0">
<Button size="xs" data-testid="filter-trigger">
<FilterLabel filters={filters} />
</Button>
<DropdownMenuTrigger>
<FilterLabel filters={filters} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent>
{filters.size > 0 ? null : (
{filters.size > 1 ? null : (
<>
<DropdownMenuCheckboxItem
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
@@ -44,7 +44,7 @@ export const TxsListNavigation = ({
</Button>
<Button
size="xs"
disabled={!hasMoreTxs || loading}
disabled={!hasMoreTxs}
onClick={() => {
nextPage();
}}
@@ -86,14 +86,18 @@ describe('Txs infinite list item', () => {
render(
<MockedProvider>
<MemoryRouter>
<TxsInfiniteListItem
type="testType"
submitter="testPubKey"
hash="testTxHash"
block="1"
code={0}
command={{}}
/>
<table>
<tbody>
<TxsInfiniteListItem
type="testType"
submitter="testPubKey"
hash="testTxHash"
block="1"
code={0}
command={{}}
/>
</tbody>
</table>
</MemoryRouter>
</MockedProvider>
);
@@ -14,9 +14,9 @@ const DEFAULT_TRUNCATE_LENGTH = 7;
export function getIdTruncateLength(screen: Screen): number {
if (['xxxl', 'xxl'].includes(screen)) {
return 64;
} else if (['xl', 'lg', 'md'].includes(screen)) {
return 32;
} else if (['xl', 'lg', 'md'].includes(screen)) {
return 16;
}
return DEFAULT_TRUNCATE_LENGTH;
}
@@ -5,11 +5,17 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
import { Side } from '@vegaprotocol/types';
import { MockedProvider } from '@apollo/client/testing';
const generateHash = (): string =>
Array.from(
{ length: 64 },
() => '0123456789ABCDEF'[Math.floor(Math.random() * 16)]
).join('');
const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
return Array.from(Array(number)).map((_) => ({
block: '87901',
index: 2,
hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F',
hash: generateHash(),
submitter:
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
type: 'Submit Order',
@@ -2,7 +2,7 @@ import { Table, TableRow } from '../table';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { getTxsDataUrl } from '../../hooks/get-txs-data-url';
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
@@ -14,7 +14,7 @@ interface TxsPerBlockProps {
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
const filters = `filters[block.height]=${blockHeight}`;
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
const url = getTxsDataUrl({ filters, count: txCount });
const {
state: { data, loading, error },
} = useFetch<BlockExplorerTransactions>(url);
@@ -0,0 +1,59 @@
import { DATA_SOURCES } from '../config';
type IGetTxsDataFirstPage = {
baseUrl?: string;
count?: number;
party?: string;
filters?: string;
};
interface IGetTxsDataPrevious extends IGetTxsDataFirstPage {
before: string;
}
interface IGetTxsDataNext extends IGetTxsDataFirstPage {
after: string;
}
type IGetTxsDataUrl =
| IGetTxsDataPrevious
| IGetTxsDataNext
| IGetTxsDataFirstPage;
export const BE_TXS_PER_REQUEST = 25;
/**
* Properly encodes the filters and parameters for a request to the block explorer
* API for transactions. As the API uses a slightly less common format for encoding
* filters, some of it is more manual than you might expect.
*
* @param params An object containing the pagination and filters
* @returns string URL to call
*/
export const getTxsDataUrl = (params: IGetTxsDataUrl) => {
const baseUrl =
params.baseUrl || `${DATA_SOURCES.blockExplorerUrl}/transactions`;
const url = new URL(baseUrl);
const count = `${params.count || BE_TXS_PER_REQUEST}`;
if ('before' in params && params.before?.length > 0) {
url.searchParams.append('last', count);
url.searchParams.append('before', params.before);
} else if ('after' in params && params.after?.length > 0) {
url.searchParams.append('first', count);
url.searchParams.append('after', params.after);
} else {
url.searchParams.append('first', count);
}
// Hacky fix for param as array
let urlAsString = url.toString();
if (params.filters && params.filters?.length > 0) {
urlAsString += '&' + params.filters.replaceAll(' ', '%20');
}
if (params.party && params.party?.length > 0) {
urlAsString += `&filters[tx.submitter]=${params.party}`;
}
return urlAsString;
};
@@ -0,0 +1,48 @@
import { getTxsDataUrl } from './get-txs-data-url'; // import the function to be tested
describe('getTxsDataUrl', () => {
it('should return the correct URL without filters and party', () => {
const params = {
count: 10,
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?first=10';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with "before" in params', () => {
const params = {
count: 5,
before: '100.1',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?last=5&before=100.1';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with "after" in params', () => {
const params = {
count: 5,
after: '222.1',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl = 'https://example.com/transactions?first=5&after=222.1';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
it('should return the correct URL with filters and party', () => {
const params = {
count: 10,
filters: 'filters[cmd.type]=Made Up Transaction',
party: '1234',
baseUrl: 'https://example.com/transactions',
};
const expectedUrl =
'https://example.com/transactions?first=10&filters[cmd.type]=Made%20Up%20Transaction&filters[tx.submitter]=1234';
expect(getTxsDataUrl(params)).toEqual(expectedUrl);
});
});
+103 -92
View File
@@ -1,130 +1,141 @@
import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import type { URLSearchParamsInit } from 'react-router-dom';
import { useCallback } from 'react';
import { useFetch } from '@vegaprotocol/react-helpers';
import type {
BlockExplorerTransactionResult,
BlockExplorerTransactions,
} from '../routes/types/block-explorer-response';
import { DATA_SOURCES } from '../config';
import isNumber from 'lodash/isNumber';
import { AllFilterOptions } from '../components/txs/tx-filter';
import type { FilterOption } from '../components/txs/tx-filter';
import { BE_TXS_PER_REQUEST, getTxsDataUrl } from './get-txs-data-url';
export interface TxsStateProps {
txsData: BlockExplorerTransactionResult[];
hasMoreTxs: boolean;
cursor: string;
previousCursors: string[];
hasPreviousPage: boolean;
export function getTypeFilters(filters?: Set<FilterOption>) {
if (!filters) {
return '';
} else if (filters.size > 1) {
return '';
}
const forcedSingleFilter = Array.from(filters)[0];
return `filters[cmd.type]=${forcedSingleFilter}`;
}
export interface IUseTxsData {
limit: number;
filters?: string;
count?: number;
before?: string;
after?: string;
party?: string;
filters?: Set<FilterOption>;
}
interface IGetTxsDataUrl {
limit: string;
filters?: string;
}
export const useTxsData = ({
count = 25,
before,
after,
filters,
party,
}: IUseTxsData) => {
const [, setSearchParams] = useSearchParams();
let hasMoreTxs = true;
let txsData: BlockExplorerTransactionResult[] = [];
export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
const url = new URL(`${DATA_SOURCES.blockExplorerUrl}/transactions`);
if (limit) {
url.searchParams.append('limit', limit);
}
// Hacky fix for param as array
let urlAsString = url.toString();
if (filters) {
urlAsString += '&' + filters.replace(' ', '%20');
}
return urlAsString;
};
export const useTxsData = ({ limit, filters }: IUseTxsData) => {
const [
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage },
setTxsState,
] = useState<TxsStateProps>({
txsData: [],
hasMoreTxs: false,
previousCursors: [],
cursor: '',
hasPreviousPage: false,
const url = getTxsDataUrl({
filters: getTypeFilters(filters),
count,
before,
after,
party,
});
const url = getTxsDataUrl({ limit: limit.toString(), filters });
const {
state: { data, error, loading },
refetch,
} = useFetch<BlockExplorerTransactions>(url, {}, true);
useEffect(() => {
if (!loading && data && isNumber(data.transactions.length)) {
setTxsState((prev) => {
return {
...prev,
txsData: data.transactions,
hasMoreTxs: data.transactions.length >= limit,
cursor: data?.transactions.at(-1)?.cursor || '',
};
});
}
}, [loading, setTxsState, data, limit]);
if (!loading && data && isNumber(data.transactions.length)) {
hasMoreTxs = data.transactions.length >= count;
txsData = data.transactions;
}
const nextPage = useCallback(() => {
const c = data?.transactions.at(0)?.cursor;
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
setTxsState((prev) => ({
...prev,
hasPreviousPage: true,
previousCursors: newPreviousCursors,
}));
return refetch({
limit,
before: cursor,
});
}, [data, previousCursors, cursor, limit, refetch]);
const after = data?.transactions.at(-1)?.cursor || '';
const params: URLSearchParamsInit = { after };
if (filters) {
params.filters = Array.from(filters).join(',');
}
setSearchParams(params);
}, [filters, data, setSearchParams]);
const previousPage = useCallback(() => {
const previousCursor = [...previousCursors].pop();
const newPreviousCursors = previousCursors.slice(0, -1);
setTxsState((prev) => ({
...prev,
hasPreviousPage: newPreviousCursors.length > 0,
previousCursors: newPreviousCursors,
}));
return refetch({
limit,
before: previousCursor,
});
}, [previousCursors, limit, refetch]);
const before = data?.transactions[0]?.cursor || '';
const params: URLSearchParamsInit = { before };
if (filters && filters.size > 0 && filters.size === 1) {
params.filters = Array.from(filters)[0];
}
setSearchParams(params);
}, [filters, data, setSearchParams]);
const refreshTxs = useCallback(async () => {
setTxsState(() => ({
txsData: [],
cursor: '',
previousCursors: [],
hasMoreTxs: false,
hasPreviousPage: false,
}));
const params: URLSearchParamsInit = {};
if (filters && filters.size > 0 && filters.size === 1) {
params.filters = Array.from(filters)[0];
}
setSearchParams(params);
refetch({ limit });
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
refetch({ count: BE_TXS_PER_REQUEST });
}, [setSearchParams, refetch, filters]);
const updateFilters = useCallback(
(newFilters: Set<FilterOption>) => {
const params: URLSearchParamsInit = {};
if (newFilters && newFilters.size === 1) {
params.filters = Array.from(newFilters)[0];
}
setSearchParams(params);
},
[setSearchParams]
);
return {
updateFilters,
txsData,
loading,
error,
hasMoreTxs,
hasPreviousPage,
previousCursors,
cursor,
refreshTxs,
nextPage,
previousPage,
};
};
/**
* Returns a Set of filters based on the URLSearchParams, or
* defaults to all.
* @param params
* @returns Set
*/
export function getInitialFilters(params: URLSearchParams): Set<FilterOption> {
const defaultFilters = new Set(AllFilterOptions);
const p = params.get('filters');
if (!p) {
return defaultFilters;
}
const filters = new Set<FilterOption>();
p.split(',').forEach((f) => {
if (AllFilterOptions.includes(f as FilterOption)) {
filters.add(f as FilterOption);
}
});
if (filters.size === 0) {
return defaultFilters;
}
return filters;
}
@@ -204,6 +204,7 @@ describe('Block', () => {
(useFetch as jest.Mock).mockReturnValue({
state: { data: createBlockResponse(1), loading: false, error: null },
});
render(renderComponent(1));
await waitFor(() => screen.getByTestId('block-header'));
expect(screen.getByTestId('previous-block-button')).toHaveAttribute(
@@ -15,9 +15,13 @@ import { PartyBlockAccounts } from './components/party-block-accounts';
import { isValidPartyId } from './components/party-id-error';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
import type { FilterOption } from '../../../components/txs/tx-filter';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { useSearchParams } from 'react-router-dom';
const Party = () => {
const [params] = useSearchParams();
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const { party } = useParams<{ party: string }>();
@@ -27,24 +31,21 @@ const Party = () => {
const partyId = toNonHex(party ? party : '');
const { isMobile } = useScreenDimensions();
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
const baseFilters = `filters[tx.submitter]=${partyId}`;
const f =
filters && filters.size === 1
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}`
: baseFilters;
const {
hasMoreTxs,
nextPage,
refreshTxs,
previousPage,
error,
refreshTxs,
loading,
txsData,
hasPreviousPage,
hasMoreTxs,
updateFilters,
} = useTxsData({
limit: 25,
filters: f,
filters: filters.size === 1 ? filters : undefined,
before: params.get('before') || undefined,
after: !params.get('before') ? params.get('after') || undefined : undefined,
party: partyId,
});
const variables = useMemo(() => ({ partyId }), [partyId]);
@@ -102,15 +103,21 @@ const Party = () => {
refreshTxs={refreshTxs}
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
hasPreviousPage={true}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} />
<TxsFilter
filters={filters}
setFilters={(f) => {
setFilters(f);
updateFilters(f as Set<FilterOption>);
}}
/>
</TxsListNavigation>
{!error && txsData ? (
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
hasMoreTxs={true}
areTxsLoading={loading}
txs={txsData}
loadMoreTxs={nextPage}
+19 -16
View File
@@ -1,14 +1,14 @@
import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../../components/route-title';
import { TxsInfiniteList } from '../../../components/txs';
import { useTxsData } from '../../../hooks/use-txs-data';
import { useTxsData, getInitialFilters } from '../../../hooks/use-txs-data';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import { useState } from 'react';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { TxsFilter } from '../../../components/txs/tx-filter';
import type { FilterOption } from '../../../components/txs/tx-filter';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
const BE_TXS_PER_REQUEST = 25;
import { useSearchParams } from 'react-router-dom';
export const TxsList = () => {
useDocumentTitle(['Transactions']);
@@ -27,25 +27,22 @@ export const TxsList = () => {
* @returns {JSX.Element} Transaction List and controls
*/
export const TxsListFiltered = () => {
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const f =
filters && filters.size === 1
? `filters[cmd.type]=${Array.from(filters)[0]}`
: '';
const [params] = useSearchParams();
const [filters, setFilters] = useState(getInitialFilters(params));
const {
hasMoreTxs,
nextPage,
previousPage,
error,
refreshTxs,
loading,
txsData,
hasPreviousPage,
hasMoreTxs,
updateFilters,
} = useTxsData({
limit: BE_TXS_PER_REQUEST,
filters: f,
filters: filters.size === 1 ? filters : undefined,
before: params.get('before') || undefined,
after: !params.get('before') ? params.get('after') || undefined : undefined,
});
return (
@@ -54,11 +51,17 @@ export const TxsListFiltered = () => {
refreshTxs={refreshTxs}
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
hasPreviousPage={true}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} />
<TxsFilter
filters={filters}
setFilters={(f) => {
setFilters(f);
updateFilters(f as Set<FilterOption>);
}}
/>
</TxsListNavigation>
<TxsInfiniteList
hasFilters={filters.size > 0}
@@ -0,0 +1,107 @@
{
"changes": {
"decimalPlaces": "5",
"positionDecimalPlaces": "5",
"linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "0",
"lpPriceRange": "10",
"instrument": {
"name": "Token test market",
"code": "Token.24h",
"future": {
"settlementAsset": "816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc",
"quoteName": "fUSDC",
"dataSourceSpecForSettlementData": {
"external": {
"oracle": {
"signers": [
{
"pubKey": {
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
}
}
],
"filters": [
{
"key": {
"name": "prices.BTC.value",
"type": "TYPE_INTEGER",
"numberDecimalPlaces": "0"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN",
"value": "0"
}
]
}
]
}
}
},
"dataSourceSpecForTradingTermination": {
"external": {
"oracle": {
"signers": [
{
"pubKey": {
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
}
}
],
"filters": [
{
"key": {
"name": "trading.terminated.ETH5",
"type": "TYPE_BOOLEAN"
},
"conditions": [
{
"operator": "OPERATOR_EQUALS",
"value": "true"
}
]
}
]
}
}
},
"dataSourceSpecBinding": {
"settlementDataProperty": "prices.BTC.value",
"tradingTerminationProperty": "trading.terminated.ETH5"
}
}
},
"metadata": ["sector:food", "sector:materials", "source:docs.vega.xyz"],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "43200",
"probability": "0.9999999",
"auctionExtension": "600"
}
]
},
"liquidityMonitoringParameters": {
"targetStakeParameters": {
"timeWindow": "3600",
"scalingFactor": 10
},
"triggeringRatio": "0.7",
"auctionExtension": "1"
},
"logNormal": {
"tau": 0.0001140771161,
"riskAversionParameter": 0.001,
"params": {
"mu": 0,
"r": 0.016,
"sigma": 0.8
}
},
"successor": {
"parentMarketId": "",
"insurancePoolFraction": "0.75"
}
}
}
@@ -220,7 +220,7 @@ context(
function () {
const proposalTitle = 'Test new market proposal';
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId(newProposalTitle).type('Test new market proposal');
cy.getByTestId(newProposalTitle).type(proposalTitle);
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
const newMarketPayload = JSON.stringify(newMarketProposal);
@@ -606,6 +606,94 @@ context(
});
});
it('able to submit successor market proposal', function () {
const proposalTitle = 'Test successor market proposal';
cy.createMarket();
cy.reload();
waitForSpinner();
cy.getByTestId('closed-proposals').within(() => {
cy.contains('Add Lorem Ipsum market')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.getByTestId(viewProposalBtn).click();
});
});
getProposalInformationFromTable('ID').invoke('text').as('parentMarketId');
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId(newProposalTitle).type(proposalTitle);
cy.getByTestId(newProposalDescription).type(
'E2E test for successor market'
);
cy.fixture('/proposals/successor-market').then((newMarketProposal) => {
newMarketProposal.changes.successor.parentMarketId =
this.parentMarketId;
const newMarketPayload = JSON.stringify(newMarketProposal);
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
cy.wrap(
getDownloadedProposalJsonPath('vega-new-market-proposal-')
).then((filePath) => {
goToMakeNewProposal(governanceProposalType.RAW);
submitUniqueRawProposal({ proposalBody: filePath });
});
});
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => {
// 3003-PMAN-008
cy.getByTestId('proposal-successor-info')
.should('have.text', 'Successor market to: TEST.24h')
.find('a')
.should('have.attr', 'href')
.and('contain', this.parentMarketId);
cy.getByTestId('view-proposal-btn').click();
});
// #3003-PMAN-010
cy.getByTestId(proposalJsonToggle).click();
cy.get('.language-json').within(() => {
cy.get('.hljs-attr').should('contain.text', 'parentMarketId');
cy.get('.hljs-string').should('contain.text', this.parentMarketId);
cy.get('.hljs-attr').should('contain.text', 'insurancePoolFraction');
cy.get('.hljs-string').should('contain.text', '0.75');
});
cy.getByTestId('proposal-market-data').within(() => {
cy.getByTestId('proposal-market-data-toggle').click();
cy.contains('Key details').click();
// 3003-PMAN-009
getMarketProposalDetailsFromTable('Parent Market ID').should(
'have.text',
this.parentMarketId
);
getMarketProposalDetailsFromTable('Insurance Pool Fraction').should(
'have.text',
'0.75'
);
getMarketProposalDetailsFromTable('Trading Mode').should(
'have.text',
'No trading'
);
});
// 3003-PMAN-011
cy.contains('Parent Market ID').realHover();
cy.getByTestId('tooltip-content').should(
'contain.text',
'The ID of the market this market succeeds.'
);
cy.contains('Insurance Pool Fraction').realHover();
cy.getByTestId('tooltip-content').should(
'contain.text',
'The fraction of the insurance pool balance that is carried over from the parent market to the successor.'
);
});
after('Disassociate from second wallet key if present', function () {
cy.reload();
waitForSpinner();
@@ -96,12 +96,14 @@ context('rewards - flow', { tags: '@slow' }, function () {
.within(() => {
cy.get('h2').first().should('contain.text', 'EPOCH');
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut)
.should('contain.text', '0.4415')
.and('contain.text', '(44.15%)');
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
.should('contain.text', '0.0004')
.and('contain.text', '(44.15%)');
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD', rewardsTimeOut).should(
'contain.text',
'0.4415'
);
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE').should(
'contain.text',
'0.0004'
);
cy.getByTestId('total').should('have.text', '0.4419');
});
});
@@ -339,7 +339,7 @@ context(
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name)
.parent()
.siblings()
.siblings(txTimeout)
.should((elementAmount) => {
const displayedAmount = parseFloat(elementAmount.text());
expect(displayedAmount).be.gte(expectedAmount);
@@ -107,7 +107,7 @@ export function dissociateFromSecondWalletKey() {
cy.getByTestId('vega-in-wallet')
.first()
.within(() => {
cy.getByTestId('eth-wallet-associated-balances')
cy.getByTestId('eth-wallet-associated-balances', txTimeout)
.last()
.within(() => {
cy.getByTestId('associated-key')
@@ -78,13 +78,21 @@ export function stakingPageAssociateTokens(
}
cy.get(tokenAmountInputBox, epochTimeout).type(amount);
if (approve) {
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
'be.visible'
);
cy.contains('Approve $VEGA Tokens for staking on Vega', txTimeout).should(
'not.exist'
);
cy.getByTestId('wallet-associate').then((walletAssociateField) => {
if (
walletAssociateField.find('[data-testid="token-input-approve-button"]')
.length
) {
cy.get(tokenInputApprove, txTimeout).should('be.enabled').click();
cy.contains('Approve $VEGA Tokens for staking on Vega').should(
'be.visible'
);
cy.contains(
'Approve $VEGA Tokens for staking on Vega',
txTimeout
).should('not.exist');
}
});
}
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
+2 -1
View File
@@ -16,6 +16,7 @@ NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
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
@@ -25,4 +26,4 @@ CYPRESS_FAIRGROUND=false
LC_ALL="en_US.UTF-8"
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_SUCCESSOR_MARKETS=true
+2 -1
View File
@@ -17,6 +17,7 @@ NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
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_TENDERMINT_URL=http://localhost:26617
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
@@ -25,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
+2 -1
View File
@@ -11,10 +11,11 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n00.devnet1.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
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
+2 -1
View File
@@ -13,9 +13,10 @@ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4
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_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
+2 -1
View File
@@ -12,9 +12,10 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
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_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
+2 -1
View File
@@ -8,9 +8,10 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
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_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
+2 -1
View File
@@ -12,10 +12,11 @@ NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
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
+2 -1
View File
@@ -9,10 +9,11 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
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
+2 -7
View File
@@ -18,10 +18,7 @@ import { VegaWallet } from '../vega-wallet';
import { useLocation, useMatch } from 'react-router-dom';
import { useEffect } from 'react';
import { useTelemetryDialog } from '../telemetry-dialog/telemetry-dialog';
import {
ProtocolUpgradeCountdown,
ProtocolUpgradeCountdownMode,
} from '@vegaprotocol/proposals';
import { ProtocolUpgradeCountdown } from '@vegaprotocol/proposals';
export const SettingsLink = () => {
const { open, isOpen, close } = useTelemetryDialog();
@@ -68,9 +65,7 @@ export const Nav = ({ theme }: Pick<NavigationProps, 'theme'>) => {
actions={
<>
<SettingsLink />
<ProtocolUpgradeCountdown
mode={ProtocolUpgradeCountdownMode.IN_ESTIMATED_TIME_REMAINING}
/>
<ProtocolUpgradeCountdown />
</>
}
>
+1
View File
@@ -66,6 +66,7 @@ export const ENV = {
ethWalletMnemonic: windowOrDefault('NX_ETH_WALLET_MNEMONIC'),
localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
delegationsPagination: windowOrDefault('NX_DELEGATIONS_PAGINATION'),
rest: windowOrDefault('NX_VEGA_REST_URL'),
addresses:
ContractAddresses[(envName === 'local' ? 'CUSTOM' : envName) as Networks],
};
+1 -1
View File
@@ -20,6 +20,6 @@ export const downloadJson = (jsonString: string, proposalTitle: string) => {
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
} catch (error) {
console.log(error);
console.error(error);
}
};
@@ -200,7 +200,7 @@ export const ProposalMarketData = ({
title={marketData.tradableInstrument.instrument.code}
open={isOpen}
onChange={(isOpen) => (isOpen ? open() : close())}
size="medium"
size="large"
dataTestId="market-json-dialog"
>
<CopyWithTooltip text={JSON.stringify(marketData)}>
@@ -6,6 +6,7 @@ import { Proposal } from '../components/proposal';
import { ProposalNotFound } from '../components/proposal-not-found';
import { useProposalQuery } from './__generated__/Proposal';
import { useFetch } from '@vegaprotocol/react-helpers';
import { ENV } from '../../../config';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
import { useAssetQuery } from '@vegaprotocol/assets';
@@ -13,11 +14,8 @@ import {
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import { useEnvironment } from '@vegaprotocol/environment';
export const ProposalContainer = () => {
const { VEGA_REST_URL } = useEnvironment();
const REST_ENDPOINT = VEGA_REST_URL;
const [
mostRecentlyEnactedAssociatedMarketProposal,
setMostRecentlyEnactedAssociatedMarketProposal,
@@ -47,7 +45,7 @@ export const ProposalContainer = () => {
const {
state: { data: restData, loading: restLoading, error: restError },
} = useFetch(`${REST_ENDPOINT}governance?proposalId=${params.proposalId}`);
} = useFetch(`${ENV.rest}governance?proposalId=${params.proposalId}`);
const { data, loading, error, refetch } = useProposalQuery({
fetchPolicy: 'network-only',
@@ -63,7 +61,7 @@ export const ProposalContainer = () => {
error: originalMarketProposalRestError,
},
} = useFetch(
`${REST_ENDPOINT}governance?proposalId=${
`${ENV.rest}governance?proposalId=${
data?.proposal?.terms.change.__typename === 'UpdateMarket' &&
data?.proposal.terms.change.marketId
}`,
@@ -79,7 +77,7 @@ export const ProposalContainer = () => {
error: previouslyEnactedMarketProposalsRestError,
},
} = useFetch(
`${REST_ENDPOINT}governances?proposalState=STATE_ENACTED&proposalType=TYPE_UPDATE_MARKET`,
`${ENV.rest}governances?proposalState=STATE_ENACTED&proposalType=TYPE_UPDATE_MARKET`,
undefined,
true,
data?.proposal?.terms.change.__typename !== 'UpdateMarket'
@@ -5,7 +5,6 @@ import {
RewardsTable,
} from '../shared-rewards-table-assets/shared-rewards-table-assets';
import type { EpochIndividualReward } from './generate-epoch-individual-rewards-list';
import { useTranslation } from 'react-i18next';
interface EpochIndividualRewardsGridProps {
data: EpochIndividualReward;
@@ -22,14 +21,11 @@ interface RewardItemProps {
const DisplayReward = ({
reward,
decimals,
percentageOfTotal,
}: {
reward: string;
decimals: number;
percentageOfTotal?: string;
}) => {
const { t } = useTranslation();
if (Number(reward) === 0) {
return <span className="text-vega-dark-300">-</span>;
}
@@ -39,23 +35,12 @@ const DisplayReward = ({
description={
<div className="flex flex-col items-start">
<span>{formatNumber(toBigNum(reward, decimals), decimals)}</span>
{percentageOfTotal && (
<span className="text-vega-dark-300">
({percentageOfTotal}% {t('ofTotalDistributed')})
</span>
)}
</div>
}
>
<button>
<div className="flex flex-col items-start">
<span>{formatNumber(toBigNum(reward, decimals), 4)}</span>
{percentageOfTotal && (
<span className="text-vega-dark-300">
({formatNumber(percentageOfTotal, 4).toString()}
%)
</span>
)}
</div>
</button>
</Tooltip>
@@ -168,17 +168,6 @@ describe('generateEpochIndividualRewardsList', () => {
expect(result2[1].epoch).toEqual(1);
});
it('correctly calculates the total value of rewards for an asset', () => {
const rewards = [reward1, reward4];
const result = generateEpochIndividualRewardsList({
rewards,
epochId: 1,
epochRewardSummaries: [],
});
expect(result[0].rewards[0].totalAmount).toEqual('200');
});
it('returns data in the expected shape', () => {
// Just sanity checking the whole structure here
const rewards = [reward1, reward2, reward3, reward4];
@@ -458,69 +447,4 @@ describe('generateEpochIndividualRewardsList', () => {
},
]);
});
it('correctly calculates the percentage of two or more rewards by referencing the total rewards amount', () => {
const result = generateEpochIndividualRewardsList({
rewards: [
// reward1 is 100 usd, which is 10% of the total rewards amount
reward1,
{
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
amount: '200',
percentageOfTotal: '0.2',
receivedAt: new Date(),
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
party: { id: 'blah' },
epoch: { id: '1' },
},
],
epochId: 1,
epochRewardSummaries: [
{
__typename: 'EpochRewardSummary',
epoch: 1,
assetId: 'usd',
amount: '1000',
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
},
],
});
expect(result[0]).toEqual({
epoch: 1,
rewards: [
{
asset: 'USD',
decimals: 6,
totalAmount: '300',
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '300',
percentageOfTotal: '30',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
amount: '0',
percentageOfTotal: '0',
},
},
},
],
});
});
});
@@ -59,7 +59,6 @@ export const generateEpochIndividualRewardsList = ({
const epochIndividualRewards = rewards.reduce((acc, reward) => {
const epochId = reward.epoch.id;
const assetName = reward.asset.name;
const assetId = reward.asset.id;
const assetDecimals = reward.asset.decimals;
const rewardType = reward.rewardType;
const amount = reward.amount;
@@ -77,13 +76,6 @@ export const generateEpochIndividualRewardsList = ({
const epoch = acc.get(epochId);
// matchingTotalReward is the total awarded for all users for the reward type in the epoch of the asset
const matchingTotalRewardAmount = epochRewardSummaries.find(
(summary) =>
summary.epoch === Number(epochId) &&
summary.assetId === assetId &&
summary.rewardType === rewardType
)?.amount;
let asset = epoch?.rewards.find((r) => r.asset === assetName);
if (!asset) {
@@ -106,14 +98,7 @@ export const generateEpochIndividualRewardsList = ({
asset.rewardTypes[rewardType] = {
amount: newAmount,
percentageOfTotal: matchingTotalRewardAmount
? new BigNumber(newAmount)
.dividedBy(matchingTotalRewardAmount)
.multipliedBy(100)
.toString()
: // this should never be reached, if there's an individual reward there should
// always be a reward total from the api too, but set it as a fallback just in case
percentageOfTotal,
percentageOfTotal: percentageOfTotal,
};
}
@@ -61,8 +61,6 @@ export const RewardsPage = () => {
error: paramsError,
} = useNetworkParams([NetworkParams.reward_staking_delegation_payoutDelay]);
console.log('params', params);
const payoutDuration = useMemo(() => {
if (!params) {
return 0;
@@ -57,7 +57,7 @@ const ROWS = [
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
return (
<Dialog size="medium" open={isOpen} onChange={onChange}>
<Dialog size="large" open={isOpen} onChange={onChange}>
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
{t('Health')}
</h1>
@@ -535,6 +535,7 @@ function checkIfDataAndTimeOfCreationAndUpdateIsEqual(date: string) {
// unexpected latency
const minBefore = subSeconds(new Date(), 5);
const maxAfter = addSeconds(new Date(), 5);
// eslint-disable-next-line no-console
console.log(maxAfter);
const date = new Date($dateTime.toString());
expect(isAfter(date, minBefore) && isBefore(date, maxAfter)).to.equal(
@@ -2,6 +2,7 @@ describe('charts', { tags: '@smoke' }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.getByTestId('Depth').click();
@@ -202,6 +202,7 @@ describe('Closed markets', { tags: '@smoke' }, () => {
const specDataConnection = createDataConnection();
before(() => {
cy.setOnBoardingViewed();
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
@@ -455,6 +456,7 @@ describe('no closed markets', { tags: '@smoke', testIsolation: true }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/all');
cy.get('[data-testid="Closed markets"]').click();
});
@@ -4,6 +4,7 @@ const nodeHealthTrigger = 'node-health-trigger';
describe('home', { tags: '@regression' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
@@ -68,22 +69,4 @@ describe('home', { tags: '@regression' }, () => {
cy.getByTestId('connect').click();
});
});
describe('Network switcher', () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
});
it('switch to fairground network and check status & incidents link', () => {
// 0006-NETW-002
// 0006-NETW-003
cy.getByTestId('navigation')
.find('[data-testid="network-switcher"]')
.should('have.text', 'Custom')
.click();
cy.getByTestId('network-item').contains('Fairground testnet');
});
});
});
+38 -37
View File
@@ -2,7 +2,7 @@ import { aliasGQLQuery } from '@vegaprotocol/cypress';
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import * as Schema from '@vegaprotocol/types';
const dialogContent = 'dialog-content';
const dialogContent = 'welcome-dialog';
const generateProposal = (code: string): ProposalListFieldsFragment => ({
__typename: 'Proposal',
@@ -140,43 +140,43 @@ describe('home', { tags: '@regression' }, () => {
cy.wait('@MarketsData');
});
it('redirects to market/all and displays welcome notice', () => {
it('close welcome dialog should redirect to market/all', () => {
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.getByTestId('welcome-notice-title').should(
'contain.text',
'Welcome to Console'
);
});
});
describe('no proposal nor markets found', () => {
it('there are welcome text and a link to propose market', () => {
cy.mockGQL((req) => {
const data = {
marketsConnection: {
__typename: 'MarketConnection',
edges: [],
},
};
aliasGQLQuery(req, 'Markets', data);
aliasGQLQuery(req, 'MarketsData', data);
aliasGQLQuery(req, 'ProposalsList', {
proposalsConnection: {
__typename: 'ProposalsConnection',
edges: null,
},
});
cy.getByTestId('welcome-dialog').should('be.visible');
cy.getByTestId('welcome-title').should('contain.text', 'Console CUSTOM');
cy.getByTestId('browse-markets-button').should('not.be.disabled');
cy.getByTestId('get-started-banner').should('be.visible');
cy.getByTestId('get-started-button').should('not.be.disabled');
cy.getByTestId('dialog-close').click();
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
'true'
);
});
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsData');
cy.getByTestId('welcome-notice-title').should(
'contain.text',
'Welcome to Console'
);
cy.getByTestId('external-link')
.contains('Propose a market')
.should('exist');
});
it('click browse markets button should redirect to market/all', () => {
cy.getByTestId('welcome-dialog').should('be.visible');
cy.getByTestId('browse-markets-button').click();
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
'true'
);
});
});
it('click get started button should open connect dialog', () => {
cy.getByTestId('welcome-dialog').should('be.visible');
cy.getByTestId('get-started-button').click();
cy.url().should('eq', Cypress.config().baseUrl + `/#/markets/all`);
cy.window().then((window) => {
expect(window.localStorage.getItem('vega_onboarding_viewed')).to.equal(
'true'
);
});
cy.getByTestId('wallet-dialog-title').should('contain.text', 'Connect');
});
});
@@ -185,7 +185,7 @@ describe('home', { tags: '@regression' }, () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-1');
cy.visit('/');
cy.wait('@Markets');
cy.getByTestId('dialog-close').click();
cy.location('hash').should('equal', '#/markets/market-1');
cy.getByTestId(dialogContent).should('not.exist');
});
@@ -199,6 +199,7 @@ describe('home', { tags: '@regression' }, () => {
});
cy.visit('/');
cy.wait('@Markets');
cy.getByTestId('dialog-close').click();
cy.location('hash').should('equal', '#/markets/market-not-existing');
cy.getByTestId(dialogContent).should('not.exist');
});
@@ -3,12 +3,13 @@ import type { MarketsQuery } from '@vegaprotocol/markets';
import * as Schema from '@vegaprotocol/types';
const rowSelector =
'[data-testid="tab-all-markets"] .ag-center-cols-container .ag-row';
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row';
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
describe('markets all table', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.clearLocalStorage().then(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
@@ -34,7 +35,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
'Settlement asset',
'',
];
cy.getByTestId('tab-all-markets').within(($headers) => {
cy.getByTestId('tab-open-markets').within(($headers) => {
cy.wrap($headers)
.get('.ag-header-cell-text')
.each(($header, i) => {
@@ -44,7 +45,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
});
it('markets tab should be rendered properly', () => {
cy.get('[data-testid="All markets"]').should(
cy.get('[data-testid="Open markets"]').should(
'have.attr',
'data-state',
'active'
@@ -166,7 +167,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
'ETHBTC.QM21',
'SOLUSD',
];
cy.get('[data-testid="All markets"]').click({ force: true });
cy.get('[data-testid="Open markets"]').click({ force: true });
cy.url().should('eq', Cypress.config('baseUrl') + '/#/markets/all');
cy.contains('AAPL.MF21').should('be.visible');
cy.get('.ag-header-cell-label').contains('Market').click(); // sort by market name
@@ -191,7 +192,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
});
});
describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
describe('no open markets', { tags: '@smoke', testIsolation: true }, () => {
before(() => {
cy.mockTradingPage();
const markets: MarketsQuery = {};
@@ -199,11 +200,12 @@ describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
aliasGQLQuery(req, 'Markets', markets);
});
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/all');
});
it.skip('can see no markets message', () => {
// 6001-MARK-048
cy.getByTestId('tab-all-markets').should('contain.text', 'No markets');
cy.getByTestId('tab-open-markets').should('contain.text', 'No markets');
});
});
@@ -21,6 +21,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
});
before(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage(MarketState.STATE_ACTIVE);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -36,6 +36,7 @@ const headers = [
describe('liquidity table - trading', { tags: '@smoke' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockSubscription();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
@@ -119,6 +120,7 @@ describe('liquidity table - trading', { tags: '@smoke' }, () => {
describe('liquidity table view', { tags: '@smoke' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockSubscription();
cy.mockTradingPage(
Schema.MarketState.STATE_ACTIVE,
@@ -12,6 +12,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-1');
});
cy.setOnBoardingViewed();
cy.mockTradingPage(
MarketState.STATE_ACTIVE,
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
@@ -30,6 +30,7 @@ describe('Market trading page', () => {
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@MarketData');
cy.getByTestId(marketSummaryBlock).should('be.visible');
@@ -9,6 +9,7 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/all');
cy.get('[data-testid="Proposed markets"]').click();
});
@@ -84,7 +85,7 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
.find('button')
.click();
const dropdownContent = '[data-testid="market-actions-content"]';
const dropdownContent = '[data-testid="proposal-actions-content"]';
const dropdownContentItem = '[role="menuitem"]';
// 6001-MARK-059
@@ -100,7 +101,6 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
'VEGA_TOKEN_URL'
)}/proposals/e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829`
);
cy.getByTestId('market-actions-content').click();
});
// 6001-MARK-060
@@ -214,11 +214,13 @@ describe('no markets proposed', { tags: '@smoke', testIsolation: true }, () => {
aliasGQLQuery(req, 'ProposalsList', proposal);
});
cy.mockSubscription();
cy.visit('/#/markets/all');
cy.get('[data-testid="Proposed markets"]').click();
cy.setOnBoardingViewed();
});
it('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');
});
@@ -12,6 +12,7 @@ describe('markets table', { tags: '@smoke' }, () => {
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/all');
});
});
@@ -1,114 +0,0 @@
import { mockConnectWallet } from '@vegaprotocol/cypress';
describe('Navbar', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.clearAllLocalStorage();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsData');
});
const pages = [
{ name: 'Markets', link: '#/markets/all' },
{ name: 'Trading', link: '#/markets' },
{ name: 'Portfolio', link: '#/portfolio' },
];
describe('desktop view', () => {
pages.forEach(({ name, link }) => {
it(`${name} should be correctly rendered`, () => {
cy.get('nav')
.find(`a[data-testid=${name}]:visible`)
.then((element) => {
cy.wrap(element).click();
cy.location('hash').should('contain', link);
});
});
});
it('Resources dropdown should be correctly rendered', () => {
const resourceSelector = 'ul li:contains(Resources)';
['Docs', 'Give Feedback'].forEach((text, index) => {
cy.get('nav').find(resourceSelector).contains('Resources').click();
cy.get('nav')
.find(resourceSelector)
.find('.navigation-content li')
.eq(index)
.find('a')
.then((element) => {
expect(element.attr('target')).to.eq('_blank');
expect(element.attr('href')).to.not.be.empty;
expect(element.text()).to.eq(text);
});
});
});
it('Disclaimer should be presented after choosing from menu', () => {
cy.get('nav')
.find('ul li:contains(Resources)')
.contains('Resources')
.click();
cy.getByTestId('Disclaimer').eq(0).click();
cy.location('hash').should('equal', '#/disclaimer');
cy.get('p').contains(
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets.'
);
});
});
describe('mobile view', () => {
const viewportHeight = Cypress.config('viewportHeight');
const viewportWidth = Cypress.config('viewportWidth');
before(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth: 560,
viewportHeight: 890,
});
cy.viewport(560, 890);
});
describe('wallet drawer', () => {
it('wallet drawer should be correctly rendered', () => {
mockConnectWallet();
cy.connectVegaWallet(true);
cy.getByTestId('connect-vega-wallet-mobile').click();
cy.getByTestId('wallets-drawer').should('be.visible');
cy.getByTestId('wallets-drawer').within((el) => {
cy.wrap(el).get('button').contains('Disconnect').click();
});
cy.getByTestId('wallets-drawer').should('not.be.visible');
});
});
describe('menu drawer', () => {
pages.forEach(({ name, link }) => {
it(`${name} should be correctly rendered`, () => {
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('menu-drawer').within((el) => {
cy.wrap(el).getByTestId(name).click();
cy.location('hash').should('contain', link);
});
});
});
it('Menu drawer should not be visible until opened', () => {
cy.getByTestId('menu-drawer').should('not.be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('be.visible');
cy.getByTestId('button-menu-drawer').click();
cy.getByTestId('menu-drawer').should('not.be.visible');
});
});
after(() => {
// a little hack to keep the viewport size between tests (cypress bug)
Cypress.config({
viewportWidth,
viewportHeight,
});
});
});
});
@@ -6,6 +6,7 @@ const oracleFullProfile = 'oracle-full-profile';
describe('oracle information', { tags: '@smoke' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage(
MarketState.STATE_ACTIVE,
undefined,
@@ -14,6 +14,7 @@ const resPrice = 'price-990';
describe('order book', { tags: '@smoke' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
@@ -4,6 +4,7 @@ describe('Settings page', { tags: '@smoke' }, () => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/');
// Only click if not already active otherwise sidebar will close
@@ -77,6 +77,7 @@ function getButtonSelectorByText(text: string): string {
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
@@ -171,6 +172,7 @@ describe(
.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));
@@ -14,6 +14,7 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
cy.mockTradingPage();
cy.mockSubscription();
cy.clearAllLocalStorage();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
@@ -28,16 +29,16 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
it('must be able to select order direction - long/short', function () {
// 7002-SORD-004
cy.getByTestId(toggleShort).click().children('input').should('be.checked');
cy.getByTestId(toggleLong).click().children('input').should('be.checked');
cy.getByTestId(toggleShort).click().next('input').should('be.checked');
cy.getByTestId(toggleLong).click().next('input').should('be.checked');
});
it('must be able to select order type - limit/market', function () {
// 7002-SORD-005
// 7002-SORD-006
// 7002-SORD-007
cy.getByTestId(toggleLimit).click().children('input').should('be.checked');
cy.getByTestId(toggleMarket).click().children('input').should('be.checked');
cy.getByTestId(toggleLimit).click().next('input').should('be.checked');
cy.getByTestId(toggleMarket).click().next('input').should('be.checked');
});
it('order connect vega wallet button should connect', () => {
@@ -51,7 +52,7 @@ describe('deal ticket basics', { tags: '@smoke' }, () => {
.click();
cy.wait('@walletReq');
cy.getByTestId(placeOrderBtn).should('be.visible');
cy.getByTestId(toggleLimit).children('input').should('be.checked');
cy.getByTestId(toggleLimit).next('input').should('be.checked');
cy.getByTestId(orderPriceField).should('have.value', '101');
});
});
@@ -15,6 +15,7 @@ describe('time in force validation', { tags: '@smoke' }, () => {
cy.mockTradingPage();
cy.mockSubscription();
cy.clearAllLocalStorage();
cy.setOnBoardingViewed();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
@@ -7,7 +7,7 @@ const closePosition = 'close-position';
const dialogCloseX = 'dialog-close';
const dialogContent = 'dialog-content';
const dropDownMenu = 'dropdown-menu';
const marketActionsContent = 'market-actions-content';
const marketActionsContent = 'position-actions-content';
const positions = 'Positions';
const tabPositions = 'tab-positions';
const toastContent = 'toast-content';
@@ -9,6 +9,7 @@ describe('trades', { tags: '@smoke' }, () => {
before(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.intercept('POST', '/graphql', (req) => {
if (req.body.operationName === 'Trades') {
req.alias = '@Trades';
@@ -17,6 +17,7 @@ describe(
cy.visit('/#/portfolio');
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
});
@@ -122,6 +123,7 @@ describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => {
cy.visit('/#/portfolio');
cy.mockTradingPage();
cy.mockSubscription();
cy.setOnBoardingViewed();
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
});
@@ -0,0 +1,191 @@
import { selectAsset } from '../support/helpers';
const amountField = 'input[name="amount"]';
const transferText = 'transfer-intro-text';
const errorText = 'input-error-text';
const formFieldError = 'input-error-text';
const includeTransferFeeRadioBtn = 'include-transfer-fee';
const keyID = `[data-testid="${transferText}"] > .rounded-md`;
const manageVegaWallet = 'manage-vega-wallet';
const submitTransferBtn = '[type="submit"]';
const toAddressField = '[name="toAddress"]';
const totalTransferfee = 'total-transfer-fee';
const transferAmount = 'transfer-amount';
const transferForm = 'transfer-form';
const transferFee = 'transfer-fee';
const walletTransfer = 'wallet-transfer';
const ASSET_EURO = 1;
const ASSET_SEPOLIA_TBTC = 2;
describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/');
cy.getByTestId(manageVegaWallet).click();
cy.getByTestId(walletTransfer).click();
cy.wait('@Assets');
cy.wait('@Accounts');
cy.mockVegaWalletTransaction();
});
it('transfer fees tooltips', () => {
// 1003-TRAN-015
// 1003-TRAN-016
// 1003-TRAN-017
// 1003-TRAN-018
// 1003-TRAN-019
cy.getByTestId(transferForm);
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm)
.find(amountField)
.type('1', { delay: 100, force: true });
/// Check Include Transfer Fee tooltip
cy.get('label[for="include-transfer-fee"] div').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Transfer Fee tooltip
cy.contains('div', 'Transfer fee').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Amount to be transferred tooltip
cy.contains('div', 'Amount to be transferred').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Total amount (with fee) tooltip
cy.contains('div', 'Total amount (with fee)').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
});
it('transfer fees', () => {
// 1003-TRAN-020
// 1003-TRAN-021
// 1003-TRAN-022
// 1003-TRAN-023
cy.getByTestId(transferForm);
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(includeTransferFeeRadioBtn).should('be.disabled');
cy.getByTestId(transferForm)
.find(amountField)
.type('1', { delay: 100, force: true });
cy.getByTestId(transferFee)
.should('be.visible')
.should('contain.text', '0.01');
cy.getByTestId(transferAmount)
.should('be.visible')
.should('contain.text', '1.00');
cy.getByTestId(totalTransferfee)
.should('be.visible')
.should('contain.text', '1.01');
cy.getByTestId(includeTransferFeeRadioBtn).click();
cy.getByTestId(transferFee)
.should('be.visible')
.should('contain.text', '0.01');
cy.getByTestId(transferAmount)
.should('be.visible')
.should('contain.text', '0.99');
cy.getByTestId(totalTransferfee)
.should('be.visible')
.should('contain.text', '1.00');
});
});
describe(
'transfer form validation',
{ tags: '@regression', testIsolation: true },
() => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId(manageVegaWallet).click();
cy.getByTestId(walletTransfer).click();
cy.wait('@Accounts');
cy.wait('@Assets');
});
it('transfer Text', () => {
// 1003-TRAN-003
cy.getByTestId(transferText)
.should('exist')
.get(keyID)
.invoke('text')
.should('match', /[\w.]{6}…[\w.]{6}/);
});
it('invalid vega key validation', () => {
//1003-TRAN-013
//1003-TRAN-004
cy.getByTestId(transferForm).should('be.visible');
cy.contains('Enter manually').click();
cy.getByTestId(transferForm).find(toAddressField).type('asd');
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(formFieldError).should('contain.text', 'Invalid Vega key');
cy.contains('label', 'Vega key').should('be.visible');
cy.contains('label', 'Asset').should('be.visible');
cy.contains('label', 'Amount').should('be.visible');
});
it('empty fields', () => {
// 1003-TRAN-012
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(formFieldError).should('contain.text', 'Required');
cy.getByTestId(formFieldError).should('have.length', 3);
});
it('min amount', () => {
// 1002-WITH-010
// 1003-TRAN-014
selectAsset(ASSET_SEPOLIA_TBTC);
cy.get(amountField).clear().type('0');
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(errorText).should(
'contain.text',
'Value is below minimum'
);
});
it('max amount', () => {
// 1003-TRAN-002
// 1003-TRAN-011
// 1003-TRAN-002
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
cy.get(amountField).clear().type('1001', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(errorText).should(
'contain.text',
'You cannot transfer more than your available collateral'
);
});
}
);
@@ -5,205 +5,15 @@ const amountShortName = 'input[name="amount"] + div + span.text-xs';
const assetSelection = 'select-asset';
const assetBalance = 'asset-balance';
const assetOption = 'rich-select-option';
const transferText = 'transfer-intro-text';
const errorText = 'input-error-text';
const formFieldError = 'input-error-text';
const includeTransferFeeRadioBtn = 'include-transfer-fee';
const keyID = `[data-testid="${transferText}"] > .rounded-md`;
const manageVegaWallet = 'manage-vega-wallet';
const openTransferButton = 'open-transfer';
const submitTransferBtn = '[type="submit"]';
const toAddressField = '[name="toAddress"]';
const totalTransferfee = 'total-transfer-fee';
const transferAmount = 'transfer-amount';
const transferForm = 'transfer-form';
const transferFee = 'transfer-fee';
const walletTransfer = 'wallet-transfer';
const ASSET_EURO = 1;
const ASSET_SEPOLIA_TBTC = 2;
const collateralTab = 'Collateral';
const toastCloseBtn = 'toast-close';
const toastContent = 'toast-content';
describe('transfer fees', { tags: '@regression', testIsolation: true }, () => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/');
cy.wait('@Assets');
cy.wait('@Accounts');
cy.mockVegaWalletTransaction();
// Only click if not already active otherwise sidebar will close
cy.get('[data-testid="sidebar-content"]').then(($sidebarContent) => {
if ($sidebarContent.find('h2').text() !== 'Transfer') {
cy.get('[data-testid="sidebar"] [data-testid="Transfer"]').click();
}
});
});
it('transfer fees tooltips', () => {
// 1003-TRAN-015
// 1003-TRAN-016
// 1003-TRAN-017
// 1003-TRAN-018
// 1003-TRAN-019
cy.getByTestId(transferForm);
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(transferForm)
.find(amountField)
.type('1', { delay: 100, force: true });
/// Check Include Transfer Fee tooltip
cy.get('label[for="include-transfer-fee"] div').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Transfer Fee tooltip
cy.contains('div', 'Transfer fee').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Amount to be transferred tooltip
cy.contains('div', 'Amount to be transferred').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
//Check Total amount (with fee) tooltip
cy.contains('div', 'Total amount (with fee)').realHover();
cy.get('[data-side="bottom"] div')
.should('be.visible')
.should('not.be.empty');
});
it('transfer fees', () => {
// 1003-TRAN-020
// 1003-TRAN-021
// 1003-TRAN-022
// 1003-TRAN-023
cy.getByTestId(transferForm);
cy.contains('Enter manually').click();
cy.getByTestId(transferForm)
.find(toAddressField)
.type('7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535');
selectAsset(ASSET_SEPOLIA_TBTC);
cy.getByTestId(includeTransferFeeRadioBtn).should('be.disabled');
cy.getByTestId(transferForm)
.find(amountField)
.type('1', { delay: 100, force: true });
cy.getByTestId(transferFee)
.should('be.visible')
.should('contain.text', '0.01');
cy.getByTestId(transferAmount)
.should('be.visible')
.should('contain.text', '1.00');
cy.getByTestId(totalTransferfee)
.should('be.visible')
.should('contain.text', '1.01');
cy.getByTestId(includeTransferFeeRadioBtn).click();
cy.getByTestId(transferFee)
.should('be.visible')
.should('contain.text', '0.01');
cy.getByTestId(transferAmount)
.should('be.visible')
.should('contain.text', '0.99');
cy.getByTestId(totalTransferfee)
.should('be.visible')
.should('contain.text', '1.00');
});
});
describe(
'transfer form validation',
{ tags: '@regression', testIsolation: true },
() => {
beforeEach(() => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId(manageVegaWallet).click();
cy.getByTestId(walletTransfer).click();
cy.wait('@Accounts');
cy.wait('@Assets');
});
it('transfer Text', () => {
// 1003-TRAN-003
cy.getByTestId(transferText)
.should('exist')
.get(keyID)
.invoke('text')
.should('match', /[\w.]{6}…[\w.]{6}/);
});
it('invalid vega key validation', () => {
//1003-TRAN-013
//1003-TRAN-004
cy.getByTestId(transferForm).should('be.visible');
cy.contains('Enter manually').click();
cy.getByTestId(transferForm).find(toAddressField).type('asd');
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(formFieldError).should('contain.text', 'Invalid Vega key');
cy.contains('label', 'Vega key').should('be.visible');
cy.contains('label', 'Asset').should('be.visible');
cy.contains('label', 'Amount').should('be.visible');
});
it('empty fields', () => {
// 1003-TRAN-012
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(formFieldError).should('contain.text', 'Required');
cy.getByTestId(formFieldError).should('have.length', 3);
});
it('min amount', () => {
// 1002-WITH-010
// 1003-TRAN-014
selectAsset(ASSET_SEPOLIA_TBTC);
cy.get(amountField).clear().type('0');
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(errorText).should(
'contain.text',
'Value is below minimum'
);
});
it('max amount', () => {
// 1003-TRAN-002
// 1003-TRAN-011
// 1003-TRAN-002
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
cy.get(amountField).clear().type('1001', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(errorText).should(
'contain.text',
'You cannot transfer more than your available collateral'
);
});
}
);
describe('withdraw actions', { tags: '@smoke', testIsolation: true }, () => {
beforeEach(() => {
cy.mockWeb3Provider();
+4 -1
View File
@@ -1,3 +1,4 @@
import { OrderType } from '@vegaprotocol/types';
import type { OrderSubmission } from '@vegaprotocol/wallet';
const orderSizeField = 'order-size';
@@ -9,7 +10,9 @@ export const createOrder = (order: OrderSubmission): void => {
cy.log('Placing order', order);
const { type, side, size, price, timeInForce, expiresAt } = order;
cy.getByTestId(`order-type-${type}`).click();
cy.getByTestId(
`order-type-${type === OrderType.TYPE_LIMIT ? 'Limit' : 'Market'}`
).click();
cy.getByTestId(`order-side-${side}`).click();
cy.getByTestId(orderSizeField).clear().type(size);
if (price) {
+2 -2
View File
@@ -6,8 +6,8 @@ export const orderTIFDropDown = 'order-tif';
export const placeOrderBtn = 'place-order';
export const toggleShort = 'order-side-SIDE_SELL';
export const toggleLong = 'order-side-SIDE_BUY';
export const toggleLimit = 'order-type-TYPE_LIMIT';
export const toggleMarket = 'order-type-TYPE_MARKET';
export const toggleLimit = 'order-type-Limit';
export const toggleMarket = 'order-type-Market';
export const TIFlist = Object.values(Schema.OrderTimeInForce).map((value) => {
return {
+1 -1
View File
@@ -16,6 +16,6 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
NX_STOP_ORDERS=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -18,6 +18,6 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
NX_STOP_ORDERS=false
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -16,6 +16,6 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
NX_STOP_ORDERS=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+2 -2
View File
@@ -18,6 +18,6 @@ NX_APP_VERSION=v0.20.21-core-0.71.6
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
NX_STOP_ORDERS=false
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -18,6 +18,6 @@ NX_APP_VERSION=v0.20.19-core-0.71.6
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
NX_STOP_ORDERS=false
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -16,6 +16,6 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
NX_STOP_ORDERS=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -17,6 +17,6 @@ NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
# NX_STOP_ORDERS
NX_STOP_ORDERS=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
+1 -1
View File
@@ -17,6 +17,6 @@ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
# NX_STOP_ORDERS
NX_STOP_ORDERS=false
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS
@@ -0,0 +1,19 @@
import { DepositContainer } from '@vegaprotocol/deposits';
import { GetStarted } from '../../components/welcome-dialog';
import { t } from '@vegaprotocol/i18n';
export const Deposit = () => {
return (
<div className="py-16 px-8 flex w-full justify-center">
<div className="lg:min-w-[700px] min-w-[300px] max-w-[700px]">
<h1 className="text-4xl xl:text-5xl uppercase font-alpha calt">
{t('Deposit')}
</h1>
<div className="mt-10">
<DepositContainer />
<GetStarted />
</div>
</div>
</div>
);
};
@@ -0,0 +1,3 @@
import { Deposit } from './deposit';
export default Deposit;
-1
View File
@@ -23,7 +23,6 @@ export const Home = () => {
replace: true,
});
} else if (data) {
update({ shouldDisplayWelcomeDialog: true });
const marketDataId = data[0]?.id;
if (marketDataId) {
navigate(Links[Routes.MARKET](marketDataId), {
+35 -41
View File
@@ -10,7 +10,6 @@ import type { Market } from '@vegaprotocol/markets';
import { Filter } from '@vegaprotocol/orders';
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import {
ResizableGrid,
ResizableGridPanel,
@@ -58,7 +57,11 @@ const MainGrid = memo(
>
<TradeGridChild>
<Tabs storageKey="console-trade-grid-main-left">
<Tab id="chart" name={t('Chart')}>
<Tab
id="chart"
name={t('Chart')}
menu={<TradingViews.candles.menu />}
>
<TradingViews.candles.component marketId={marketId} />
</Tab>
<Tab id="depth" name={t('Depth')}>
@@ -95,57 +98,48 @@ const MainGrid = memo(
<TradeGridChild>
<Tabs storageKey="console-trade-grid-bottom">
<Tab id="positions" name={t('Positions')}>
<VegaWalletContainer>
<TradingViews.positions.component
onMarketClick={onMarketClick}
/>
</VegaWalletContainer>
<TradingViews.positions.component
onMarketClick={onMarketClick}
/>
</Tab>
<Tab id="open-orders" name={t('Open')}>
<VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Open}
/>
</VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Open}
/>
</Tab>
<Tab id="closed-orders" name={t('Closed')}>
<VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Closed}
/>
</VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Closed}
/>
</Tab>
<Tab id="rejected-orders" name={t('Rejected')}>
<VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Rejected}
/>
</VegaWalletContainer>
<TradingViews.orders.component
marketId={marketId}
filter={Filter.Rejected}
/>
</Tab>
<Tab id="orders" name={t('All')}>
<VegaWalletContainer>
<TradingViews.orders.component marketId={marketId} />
</VegaWalletContainer>
<TradingViews.orders.component marketId={marketId} />
</Tab>
{FLAGS.STOP_ORDERS ? (
<Tab id="stop-orders" name={t('Stop orders')}>
<TradingViews.stopOrders.component />
</Tab>
) : null}
<Tab id="fills" name={t('Fills')}>
<VegaWalletContainer>
<TradingViews.fills.component
marketId={marketId}
onMarketClick={onMarketClick}
/>
</VegaWalletContainer>
<TradingViews.fills.component
marketId={marketId}
onMarketClick={onMarketClick}
/>
</Tab>
<Tab id="accounts" name={t('Collateral')}>
<VegaWalletContainer>
<TradingViews.collateral.component
pinnedAsset={pinnedAsset}
onMarketClick={onMarketClick}
hideButtons
/>
</VegaWalletContainer>
<TradingViews.collateral.component
pinnedAsset={pinnedAsset}
onMarketClick={onMarketClick}
hideButtons
/>
</Tab>
</Tabs>
</TradeGridChild>
@@ -37,6 +37,7 @@ export const TradePanels = ({
const onOrderTypeClick = useMarketLiquidityClickHandler();
const [view, setView] = useState<TradingView>('candles');
const renderView = () => {
const Component = memo<{
marketId: string;
@@ -65,8 +66,23 @@ export const TradePanels = ({
);
};
const renderMenu = () => {
const viewCfg = TradingViews[view];
if ('menu' in viewCfg) {
const Menu = viewCfg.menu;
return (
<div className="flex gap-1 p-1 bg-vega-clight-800 dark:bg-vega-cdark-800 border-b border-default">
<Menu />
</div>
);
}
return null;
};
return (
<div className="h-full grid grid-rows-[min-content_1fr_min-content]">
<div className="h-full grid grid-rows-[min-content_min-content_1fr_min-content]">
<div>
{FLAGS.SUCCESSOR_MARKETS && (
<>
@@ -76,6 +92,7 @@ export const TradePanels = ({
)}
<OracleBanner marketId={market?.id || ''} />
</div>
<div>{renderMenu()}</div>
<div className="h-full">
<AutoSizer>
{({ width, height }) => (
@@ -88,9 +105,12 @@ export const TradePanels = ({
<div className="flex flex-nowrap overflow-x-auto max-w-full border-t border-default">
{Object.keys(TradingViews).map((key) => {
const isActive = view === key;
const className = classNames('p-4 min-w-[100px] capitalize', {
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
});
const className = classNames(
'py-2 px-4 min-w-[100px] capitalize text-sm',
{
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
}
);
return (
<button
data-testid={key}
@@ -2,7 +2,10 @@ import type { ComponentProps } from 'react';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { TradesContainer } from '@vegaprotocol/trades';
import { DepthChartContainer } from '@vegaprotocol/market-depth';
import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
import {
CandlesChartContainer,
CandlesMenu,
} from '@vegaprotocol/candles-chart';
import { Filter } from '@vegaprotocol/orders';
import { NO_MARKET } from './constants';
import { OrderbookContainer } from '../../components/orderbook-container';
@@ -12,6 +15,7 @@ import { AccountsContainer } from '../../components/accounts-container';
import { LiquidityContainer } from '../../components/liquidity-container';
import type { OrderContainerProps } from '../../components/orders-container';
import { OrdersContainer } from '../../components/orders-container';
import { StopOrdersContainer } from '../../components/stop-orders-container';
type MarketDependantView =
| typeof CandlesChartContainer
@@ -34,6 +38,7 @@ export const TradingViews = {
candles: {
label: 'Candles',
component: requiresMarket(CandlesChartContainer),
menu: CandlesMenu,
},
depth: {
label: 'Depth',
@@ -74,6 +79,10 @@ export const TradingViews = {
label: 'All',
component: OrdersContainer,
},
stopOrders: {
label: 'Stop',
component: StopOrdersContainer,
},
collateral: { label: 'Collateral', component: AccountsContainer },
fills: { label: 'Fills', component: FillsContainer },
};
@@ -18,7 +18,7 @@ export const MarketsPage = () => {
<div className="h-full pt-0.5 pb-3 px-1.5">
<div className="h-full my-1 border border-default rounded-sm">
<Tabs storageKey="console-markets">
<Tab id="all-markets" name={t('All markets')}>
<Tab id="open-markets" name={t('Open markets')}>
<Markets />
</Tab>
<Tab id="proposed-markets" name={t('Proposed markets')}>
@@ -71,7 +71,7 @@ export const AccountHistoryContainer = () => {
const { data: assets } = useAssetsDataProvider();
if (!pubKey) {
return <Splash>{t('Connect wallet')}</Splash>;
return <Splash>{t('Please connect Vega wallet')}</Splash>;
}
return (
@@ -13,7 +13,6 @@ import { FillsContainer } from '../../components/fills-container';
import { PositionsContainer } from '../../components/positions-container';
import { WithdrawalsContainer } from './withdrawals-container';
import { OrdersContainer } from '../../components/orders-container';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { LedgerContainer } from '../../components/ledger-container';
import { AccountHistoryContainer } from './account-history-container';
import {
@@ -62,29 +61,19 @@ export const Portfolio = () => {
<PortfolioGridChild>
<Tabs storageKey="console-portfolio-top">
<Tab id="account-history" name={t('Account history')}>
<VegaWalletContainer>
<AccountHistoryContainer />
</VegaWalletContainer>
<AccountHistoryContainer />
</Tab>
<Tab id="positions" name={t('Positions')}>
<VegaWalletContainer>
<PositionsContainer onMarketClick={onMarketClick} allKeys />
</VegaWalletContainer>
<PositionsContainer onMarketClick={onMarketClick} allKeys />
</Tab>
<Tab id="orders" name={t('Orders')}>
<VegaWalletContainer>
<OrdersContainer />
</VegaWalletContainer>
<OrdersContainer />
</Tab>
<Tab id="fills" name={t('Fills')}>
<VegaWalletContainer>
<FillsContainer onMarketClick={onMarketClick} />
</VegaWalletContainer>
<FillsContainer onMarketClick={onMarketClick} />
</Tab>
<Tab id="ledger-entries" name={t('Ledger entries')}>
<VegaWalletContainer>
<LedgerContainer />
</VegaWalletContainer>
<LedgerContainer />
</Tab>
</Tabs>
</PortfolioGridChild>
@@ -97,14 +86,10 @@ export const Portfolio = () => {
<PortfolioGridChild>
<Tabs storageKey="console-portfolio-bottom">
<Tab id="collateral" name={t('Collateral')}>
<VegaWalletContainer>
<AccountsContainer />
</VegaWalletContainer>
<AccountsContainer />
</Tab>
<Tab id="deposits" name={t('Deposits')}>
<VegaWalletContainer>
<DepositsContainer />
</VegaWalletContainer>
<DepositsContainer />
</Tab>
<Tab
id="withdrawals"
@@ -7,7 +7,6 @@ import {
import { useVegaWallet } from '@vegaprotocol/wallet';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { ViewType, useSidebar } from '../../components/sidebar';
export const WithdrawalsContainer = () => {
@@ -21,7 +20,7 @@ export const WithdrawalsContainer = () => {
const { ready, delayed } = useIncompleteWithdrawals();
return (
<VegaWalletContainer>
<>
<div className="h-full relative">
<WithdrawalsTable
data-testid="withdrawals-history"
@@ -43,6 +42,6 @@ export const WithdrawalsContainer = () => {
</Button>
</div>
)}
</VegaWalletContainer>
</>
);
};
@@ -1,8 +1,8 @@
import { useCallback } from 'react';
import { Button } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { PinnedAsset } from '@vegaprotocol/accounts';
import { AccountManager } from '@vegaprotocol/accounts';
+1 -1
View File
@@ -1,7 +1,7 @@
import { t } from '@vegaprotocol/i18n';
export const THROTTLE_UPDATE_TIME = 500;
export const RISK_ACCEPTED_KEY = 'vega_risk_accepted';
export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed';
export const MAINNET_WELCOME_HEADER = t(
'Trade cash settled futures on the fully decentralised Vega network.'
);
@@ -1,10 +1,10 @@
import { t } from '@vegaprotocol/i18n';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { FillsManager } from '@vegaprotocol/fills';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useDataGridEvents } from '@vegaprotocol/datagrid';
import { t } from '@vegaprotocol/i18n';
import { Splash } from '@vegaprotocol/ui-toolkit';
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
+1 -1
View File
@@ -17,7 +17,7 @@ export const Header = ({ title, children }: TradeMarketHeaderProps) => {
);
return (
<header className={headerClasses}>
<div className="flex flex-col justify-center items-start pl-3 lg:pl-4 pt-2 xl:pb-2 pb-0">
<div className="hidden lg:flex flex-col justify-center items-start pl-3 lg:pl-4 pt-2 xl:pb-2 pb-0">
{title}
</div>
<div data-testid="header-summary" className="min-w-0">
+3 -1
View File
@@ -1,10 +1,12 @@
import classNames from 'classnames';
export const WalletIcon = ({ className }: { className?: string }) => {
return (
<svg
width="26"
height="18"
viewBox="0 0 26 18"
className={className}
className={classNames('fill-current', className)}
data-testid="wallet-icon"
>
<path d="M4.77437 17.7499H4.74987C3.6504 17.7368 2.77439 16.8489 2.77439 15.7772V12.8495V12.6343L2.5615 12.6023C1.59672 12.4575 0.849609 11.6116 0.849609 10.6266V7.40064C0.849609 6.39018 1.59509 5.56985 2.56147 5.4249L2.77439 5.39297V5.17767V2.24998C2.77439 1.14102 3.66537 0.25 4.77437 0.25H23.7501C24.8591 0.25 25.7501 1.14098 25.7501 2.24998V15.7499C25.7501 16.8588 24.8591 17.7499 23.7501 17.7499H4.77437ZM4.44917 12.5992H4.19917L4.77441 16.075V16.325H4.77466H23.7502C24.0778 16.325 24.3254 16.0777 24.3254 15.7497V2.24984C24.3254 1.9222 24.0782 1.6746 23.7502 1.6746H4.77441C4.44677 1.6746 4.19917 1.92182 4.19917 2.24984V5.12306V5.37306H4.44917H7.0244C8.51139 5.37306 9.67508 6.56094 9.67508 8.02374V9.94852C9.67508 11.4355 8.4872 12.5992 7.0244 12.5992H4.44917ZM2.84963 6.8253C2.52199 6.8253 2.27439 7.07253 2.27439 7.40054V10.6264C2.27439 10.9541 2.52161 11.2017 2.84962 11.2017L7.02419 11.2019C7.73619 11.2019 8.25009 10.6515 8.25009 9.97598V8.0512C8.25009 7.3392 7.69976 6.8253 7.0242 6.8253H2.84963Z" />
@@ -11,9 +11,9 @@ export const LayoutWithSidebar = () => {
const gridClasses = classNames(
'h-full relative z-0 grid',
'grid-rows-[min-content_1fr]',
'grid-cols-[1fr_45px]',
'lg:grid-cols-[1fr_350px_45px]'
'grid-rows-[min-content_1fr_40px]',
'lg:grid-rows-[min-content_1fr]',
'lg:grid-cols-[1fr_350px_40px]'
);
return (
@@ -40,7 +40,14 @@ export const LayoutWithSidebar = () => {
>
<SidebarContent />
</aside>
<div className="col-start-2 lg:col-start-3 bg-vega-clight-800 dark:bg-vega-cdark-800 border-l border-default">
<div
className={classNames(
'bg-vega-clight-800 dark:bg-vega-cdark-800',
'border-t lg:border-l lg:border-t-0 border-default',
'row-start-3 col-start-1 cols-span-full',
'lg:row-start-2 lg:row-span-full lg:col-start-3'
)}
>
<Sidebar />
</div>
</div>
@@ -12,10 +12,9 @@ import {
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import type { AgGridReact } from 'ag-grid-react';
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
import { useEffect, useRef } from 'react';
import { useEffect } from 'react';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
@@ -26,8 +25,6 @@ export const LiquidityContainer = ({
marketId: string | undefined;
filter?: Filter;
}) => {
const gridRef = useRef<AgGridReact | null>(null);
const gridStore = useLiquidityStore((store) => store.gridStore);
const updateGridStore = useLiquidityStore((store) => store.updateGridStore);
@@ -60,7 +57,6 @@ export const LiquidityContainer = ({
return (
<div className="h-full relative">
<LiquidityTable
ref={gridRef}
rowData={data}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
@@ -42,8 +42,6 @@ export const LiquidityHeader = () => {
triggeringRatio,
});
console.log(market);
return (
<Header
title={
@@ -4,10 +4,12 @@ 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 } from '@vegaprotocol/markets';
import { useState } from 'react';
export const MarketHeader = () => {
const { marketId } = useParams();
const { data } = useMarket(marketId);
const [open, setOpen] = useState(false);
if (!data) return null;
@@ -15,6 +17,8 @@ export const MarketHeader = () => {
<Header
title={
<Popover
open={open}
onChange={setOpen}
trigger={
<HeaderTitle>
{data.tradableInstrument.instrument.code}
@@ -23,7 +27,10 @@ export const MarketHeader = () => {
}
alignOffset={-10}
>
<MarketSelector currentMarketId={marketId} />
<MarketSelector
currentMarketId={marketId}
onSelect={() => setOpen(false)}
/>
</Popover>
}
>
@@ -98,6 +98,7 @@ describe('MarketSelectorItem', () => {
market={market}
currentMarketId={market.id}
style={{}}
onSelect={jest.fn()}
/>
</MockedProvider>
</MemoryRouter>
@@ -17,10 +17,12 @@ export const MarketSelectorItem = ({
market,
style,
currentMarketId,
onSelect,
}: {
market: MarketMaybeWithDataAndCandles;
style: CSSProperties;
currentMarketId?: string;
onSelect: (marketId: string) => void;
}) => {
return (
<div style={style} role="row">
@@ -32,6 +34,7 @@ export const MarketSelectorItem = ({
'bg-vega-clight-600 dark:bg-vega-cdark-600':
market.id === currentMarketId,
})}
onClick={() => onSelect(market.id)}
>
<MarketData market={market} />
</Link>
@@ -80,7 +83,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
return (
<>
<div className="w-2/5" role="gridcell">
<h3 className="text-ellipsis whitespace-nowrap overflow-hidden">
<h3 className="text-ellipsis text-sm lg:text-base whitespace-nowrap overflow-hidden">
{market.tradableInstrument.instrument.code}
</h3>
{mode && (
@@ -90,7 +93,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
)}
</div>
<div
className="w-1/5 text-sm whitespace-nowrap text-ellipsis overflow-hidden"
className="w-1/5 text-xs lg:text-sm whitespace-nowrap text-ellipsis overflow-hidden"
title={instrument.product.settlementAsset.symbol}
data-testid="market-selector-price"
role="gridcell"
@@ -98,7 +101,7 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
{price} {instrument.product.settlementAsset.symbol}
</div>
<div
className="w-1/5 text-sm text-right whitespace-nowrap text-ellipsis overflow-hidden"
className="w-1/5 text-xs lg:text-sm text-right whitespace-nowrap text-ellipsis overflow-hidden"
title={t('24h vol')}
data-testid="market-selector-volume"
role="gridcell"
@@ -137,7 +137,7 @@ describe('MarketSelector', () => {
it('renders only active markets', () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
expect(screen.getAllByTestId(/market-\d/)).toHaveLength(
@@ -148,7 +148,7 @@ describe('MarketSelector', () => {
it('filters by product type', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -174,7 +174,7 @@ describe('MarketSelector', () => {
it('filters by search term', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -202,7 +202,7 @@ describe('MarketSelector', () => {
it('filters by asset', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -234,7 +234,7 @@ describe('MarketSelector', () => {
it('sorts by gained', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -256,7 +256,7 @@ describe('MarketSelector', () => {
it('sorts by lost', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -272,7 +272,7 @@ describe('MarketSelector', () => {
it('sorts by new', async () => {
render(
<MemoryRouter>
<MarketSelector currentMarketId="market-0" />
<MarketSelector currentMarketId="market-0" onSelect={jest.fn()} />
</MemoryRouter>
);
@@ -35,7 +35,7 @@ export const MarketSelector = ({
onSelect,
}: {
currentMarketId?: string;
onSelect?: (marketId: string) => void;
onSelect: (marketId: string) => void;
}) => {
const [filter, setFilter] = useState<Filter>({
searchTerm: '',
@@ -48,7 +48,7 @@ export const MarketSelector = ({
return (
<div data-testid="market-selector">
<div className="pt-2 px-2 mb-2 w-[320px] lg:w-[584px]">
<div className="pt-2 px-2 mb-2">
<ProductSelector
product={filter.product}
onSelect={(product) => {
@@ -147,16 +147,17 @@ const MarketList = ({
loading: boolean;
searchTerm: string;
currentMarketId?: string;
onSelect?: (marketId: string) => void;
onSelect: (marketId: string) => void;
noItems: string;
}) => {
const itemSize = 45;
const listRef = useRef<HTMLDivElement | null>(null);
const rect = listRef.current?.getBoundingClientRect();
// allow virtualized list to grow until it runs out of space
const height = rect
const computedHeight = rect
? Math.min(data.length * itemSize, window.innerHeight - rect.y)
: 400;
const height = Math.max(computedHeight, 45);
if (error) {
return <div>{error.message}</div>;
@@ -199,7 +200,7 @@ const MarketList = ({
interface ListItemData {
data: MarketMaybeWithDataAndCandles[];
onSelect?: (marketId: string) => void;
onSelect: (marketId: string) => void;
currentMarketId?: string;
}
@@ -216,6 +217,7 @@ const ListItem = ({
market={data.data[index]}
currentMarketId={data.currentMarketId}
style={style}
onSelect={data.onSelect}
/>
);
@@ -252,7 +254,11 @@ const List = ({
if (!data.length) {
return (
<div style={{ height }} data-testid="no-items">
<div
style={{ height }}
className="flex items-center"
data-testid="no-items"
>
<div className="mx-4 my-2 text-sm">{noItems}</div>
</div>
);
+1
View File
@@ -1 +1,2 @@
export * from './navbar';
export * from './nav-header';
@@ -0,0 +1,66 @@
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { MarketSelector } from '../market-selector';
import { useMarket } from '@vegaprotocol/markets';
import { t } from '@vegaprotocol/i18n';
import { useParams } from 'react-router-dom';
import * as PopoverPrimitive from '@radix-ui/react-popover';
import { useState } from 'react';
/**
* This is only rendered for the mobile navigation
*/
export const NavHeader = () => {
const { marketId } = useParams();
const { data } = useMarket(marketId);
const [open, setOpen] = useState(false);
if (!marketId) return null;
return (
<FullScreenPopover
open={open}
onOpenChange={(x) => {
setOpen(x);
}}
trigger={
<h1 className="flex gap-1 sm:gap-2 md:gap-4 items-center text-default text-lg whitespace-nowrap xl:pr-4 xl:border-r border-default">
{data ? data.tradableInstrument.instrument.code : t('Select market')}
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={20} />
</h1>
}
>
<MarketSelector
currentMarketId={marketId}
onSelect={() => setOpen(false)}
/>
</FullScreenPopover>
);
};
export interface PopoverProps extends PopoverPrimitive.PopoverProps {
trigger: React.ReactNode | string;
}
export const FullScreenPopover = ({
trigger,
children,
open,
onOpenChange,
}: PopoverProps) => {
return (
<PopoverPrimitive.Root open={open} onOpenChange={onOpenChange}>
<PopoverPrimitive.Trigger data-testid="popover-trigger">
{trigger}
</PopoverPrimitive.Trigger>
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
data-testid="popover-content"
className="w-screen bg-vega-clight-800 dark:bg-vega-cdark-800 text-default border border-default"
sideOffset={5}
>
{children}
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
</PopoverPrimitive.Root>
);
};
+145 -29
View File
@@ -1,42 +1,158 @@
import { render, screen } from '@testing-library/react';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { Navbar } from './navbar';
import { useGlobalStore } from '../../stores';
jest.mock('@vegaprotocol/proposals', () => ({
ProtocolUpgradeCountdown: () => null,
}));
describe('Navbar', () => {
const pubKey = 'pubKey';
it('should be properly rendered', () => {
render(
<MockedProvider>
<MemoryRouter>
<VegaWalletContext.Provider
value={{ pubKey } as VegaWalletContextShape}
>
<Navbar theme="dark" />
</VegaWalletContext.Provider>
</MemoryRouter>
</MockedProvider>
const pubKey = '000';
const pubKeys = [
{
publicKey: pubKey,
name: 'Pub key 0',
},
{
publicKey: '111',
name: 'Pub key 1',
},
];
const marketId = 'abc';
const navbarContent = 'navbar-menu-content';
const renderComponent = (
initialEntries?: string[],
walletContext?: Partial<VegaWalletContextShape>
) => {
const context = {
pubKey,
pubKeys,
selectPubKey: jest.fn(),
disconnect: jest.fn(),
...walletContext,
} as VegaWalletContextShape;
return render(
<MemoryRouter initialEntries={initialEntries}>
<VegaWalletContext.Provider value={context}>
<Navbar />
</VegaWalletContext.Provider>
</MemoryRouter>
);
expect(screen.getByTestId('Markets')).toBeInTheDocument();
expect(screen.getByTestId('Trading')).toBeInTheDocument();
expect(screen.getByTestId('Portfolio')).toBeInTheDocument();
};
beforeAll(() => {
useGlobalStore.setState({ marketId });
});
it('should be properly rendered', () => {
renderComponent();
const expectedLinks = [
['/', ''],
['/markets/all', 'Markets'],
[`/markets/${marketId}`, 'Trading'],
['/portfolio', 'Portfolio'],
];
const links = screen.getAllByRole('link');
links.forEach((link, i) => {
const [href, text] = expectedLinks[i];
expect(link).toHaveAttribute('href', href);
expect(link).toHaveTextContent(text);
});
});
it('Markets page route should not match empty market page', () => {
render(
<MockedProvider>
<MemoryRouter initialEntries={['/markets/all']}>
<VegaWalletContext.Provider
value={{ pubKey } as VegaWalletContextShape}
>
<Navbar theme="dark" />
</VegaWalletContext.Provider>
</MemoryRouter>
</MockedProvider>
renderComponent(['/markets/all']);
expect(screen.getByRole('link', { name: 'Markets' })).toHaveClass('active');
expect(screen.getByRole('link', { name: 'Trading' })).not.toHaveClass(
'active'
);
expect(screen.getByTestId('Markets')).toHaveClass('active');
expect(screen.getByTestId('Trading')).not.toHaveClass('active');
});
it('can open menu and navigate on small screens', async () => {
renderComponent();
await userEvent.click(screen.getByRole('button', { name: 'Menu' }));
const menuEl = screen.getByTestId(navbarContent);
expect(menuEl).toBeInTheDocument();
const menu = within(menuEl);
const expectedLinks = [
['/markets/all', 'Markets'],
[`/markets/${marketId}`, 'Trading'],
['/portfolio', 'Portfolio'],
];
const links = menu.getAllByRole('link');
links.forEach((link, i) => {
const [href, text] = expectedLinks[i];
expect(link).toHaveAttribute('href', href);
expect(link).toHaveTextContent(text);
});
await userEvent.click(screen.getByRole('button', { name: 'Close menu' }));
expect(screen.queryByTestId(navbarContent)).not.toBeInTheDocument();
});
it('can close menu by clicking overlay', async () => {
renderComponent();
await userEvent.click(screen.getByRole('button', { name: 'Menu' }));
expect(screen.getByTestId(navbarContent)).toBeInTheDocument();
await userEvent.click(screen.getByTestId('navbar-menu-overlay'));
expect(screen.queryByTestId(navbarContent)).not.toBeInTheDocument();
});
it('can open wallet menu on small screens and change pubkey', async () => {
const mockSelectPubKey = jest.fn();
renderComponent(undefined, { selectPubKey: mockSelectPubKey });
await userEvent.click(screen.getByRole('button', { name: 'Wallet' }));
const menuEl = screen.getByTestId(navbarContent);
expect(menuEl).toBeInTheDocument();
const menu = within(menuEl);
expect(menu.getAllByTestId(/key-\d+-mobile/)).toHaveLength(pubKeys.length);
const activeKey = within(menu.getByTestId('key-000-mobile'));
expect(activeKey.getByText(pubKeys[0].name)).toBeInTheDocument();
expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument();
const inactiveKey = within(menu.getByTestId('key-111-mobile'));
await userEvent.click(inactiveKey.getByText(pubKeys[1].name));
expect(mockSelectPubKey).toHaveBeenCalledWith(pubKeys[1].publicKey);
});
it('can transfer and close menu', async () => {
renderComponent();
await userEvent.click(screen.getByRole('button', { name: 'Wallet' }));
const menuEl = screen.getByTestId(navbarContent);
expect(menuEl).toBeInTheDocument();
const menu = within(menuEl);
await userEvent.click(menu.getByText('Transfer'));
expect(screen.queryByTestId(navbarContent)).not.toBeInTheDocument();
});
it('can disconnect and close menu', async () => {
const mockDisconnect = jest.fn();
renderComponent(undefined, { disconnect: mockDisconnect });
await userEvent.click(screen.getByRole('button', { name: 'Wallet' }));
const menuEl = screen.getByTestId(navbarContent);
expect(menuEl).toBeInTheDocument();
const menu = within(menuEl);
await userEvent.click(menu.getByText('Disconnect'));
expect(mockDisconnect).toHaveBeenCalled();
expect(screen.queryByTestId(navbarContent)).not.toBeInTheDocument();
});
});

Some files were not shown because too many files have changed in this diff Show More