Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55f8829655 |
@@ -205,7 +205,7 @@ jobs:
|
||||
# run tests
|
||||
#----------------------------------------------
|
||||
- name: Run tests
|
||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
|
||||
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 6 --dist loadfile --durations=15
|
||||
working-directory: apps/trading/e2e
|
||||
#----------------------------------------------
|
||||
# upload traces
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-trace
|
||||
path: apps/trading/e2e/traces/
|
||||
path: ./traces/
|
||||
retention-days: 15
|
||||
#----------------------------------------------
|
||||
# ----- upload logs -----
|
||||
|
||||
+2
-1
@@ -59,4 +59,5 @@ apps/trading/e2e/logs/
|
||||
apps/trading/e2e/.pytest_cache/
|
||||
apps/trading/e2e/traces/
|
||||
|
||||
.nx/
|
||||
.nx/cache
|
||||
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import { FeesContainer } from '../../components/fees-container';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const Fees = () => {
|
||||
const t = useT();
|
||||
const title = t('Fees');
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<div className="container p-4 mx-auto">
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Fees')}</h1>
|
||||
<FeesContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -95,11 +95,6 @@ const CreateCodeDialog = ({
|
||||
const { stakeAvailable: currentStakeAvailable, requiredStake } =
|
||||
useStakeAvailable();
|
||||
|
||||
const { data: referralSets } = useReferral({
|
||||
pubKey,
|
||||
role: 'referrer',
|
||||
});
|
||||
|
||||
const onSubmit = () => {
|
||||
if (isReadOnly || !pubKey) {
|
||||
setErr('Not connected');
|
||||
@@ -198,68 +193,6 @@ const CreateCodeDialog = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (!referralSets) {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
<>
|
||||
{
|
||||
<p>
|
||||
{t(
|
||||
'There is currently no referral program active, are you sure you want to create a code?'
|
||||
)}
|
||||
</p>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
{status === 'success' && code && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 min-w-0 p-2 text-sm rounded bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<p className="overflow-hidden whitespace-nowrap text-ellipsis">
|
||||
{code}
|
||||
</p>
|
||||
</div>
|
||||
<CopyWithTooltip text={code}>
|
||||
<TradingButton
|
||||
className="text-sm no-underline"
|
||||
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
||||
>
|
||||
<span>{t('Copy')}</span>
|
||||
</TradingButton>
|
||||
</CopyWithTooltip>
|
||||
</div>
|
||||
)}
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => onSubmit()}
|
||||
{...getButtonProps()}
|
||||
></TradingButton>
|
||||
{status === 'idle' && (
|
||||
<TradingButton
|
||||
fill={true}
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
refetch();
|
||||
setDialogOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('No')}
|
||||
</TradingButton>
|
||||
)}
|
||||
{err && <InputError>{err}</InputError>}
|
||||
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
||||
<ExternalLink href={ABOUT_REFERRAL_DOCS_LINK}>
|
||||
{t('About the referral program')}
|
||||
</ExternalLink>
|
||||
<ExternalLink href={DISCLAIMER_REFERRAL_DOCS_LINK}>
|
||||
{t('Disclaimer')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{(status === 'idle' || status === 'loading' || status === 'error') && (
|
||||
|
||||
@@ -6,12 +6,7 @@ import { BORDER_COLOR, GRADIENT } from './constants';
|
||||
import { Tag } from './tag';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
DApp,
|
||||
DocsLinks,
|
||||
TOKEN_PROPOSALS,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { DApp, TOKEN_PROPOSALS, useLinks } from '@vegaprotocol/environment';
|
||||
import { useT, ns } from '../../lib/use-t';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
@@ -93,19 +88,10 @@ export const TiersContainer = () => {
|
||||
return (
|
||||
<div className="text-base px-5 py-10 text-center">
|
||||
<Trans
|
||||
defaults="There are currently no active referral programs. Check the <0>Governance App</0> to see if there are any proposals in progress and vote."
|
||||
defaults="We're sorry but we don't have an active referral programme currently running. You can propose a new programme <0>here</0>."
|
||||
components={[
|
||||
<ExternalLink href={governanceLink(TOKEN_PROPOSALS)} key="link">
|
||||
{t('Governance App')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
/>
|
||||
<Trans
|
||||
defaults="You can propose a new program via the <0>Docs</0>."
|
||||
components={[
|
||||
<ExternalLink href={DocsLinks?.REFERRALS} key="link">
|
||||
{t('Docs')}
|
||||
{t('here')}
|
||||
</ExternalLink>,
|
||||
]}
|
||||
ns={ns}
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { RewardsContainer } from '../../components/rewards-container';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const Rewards = () => {
|
||||
const t = useT();
|
||||
const title = t('Rewards');
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<h1 className="px-4 pb-4 text-2xl">{t('Rewards')}</h1>
|
||||
<RewardsContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
if (edge.node.endTime) {
|
||||
acc?.push({
|
||||
endTime: fromNanoSeconds(edge.node.endTime),
|
||||
fundingRate: Number(edge.node.fundingRate),
|
||||
fundingRate: Number(edge.node.fundingRate) * 100,
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
@@ -82,8 +82,7 @@ export const FundingContainer = ({ marketId }: { marketId: string }) => {
|
||||
<LineChart
|
||||
data={values}
|
||||
theme={theme}
|
||||
priceFormat={(fundingRate) => `${(fundingRate * 100).toFixed(4)}%`}
|
||||
yAxisTickFormat="%"
|
||||
priceFormat={(fundingRate) => `${fundingRate.toFixed(4)}%`}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { Settings } from './settings';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
describe('Settings', () => {
|
||||
it('should the settings component with all the options', () => {
|
||||
render(<Settings />);
|
||||
expect(screen.getByText('Dark mode')).toBeInTheDocument();
|
||||
expect(screen.getByText('Share usage data')).toBeInTheDocument();
|
||||
expect(screen.getByText('Toast location')).toBeInTheDocument();
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,7 @@
|
||||
import {
|
||||
Dialog,
|
||||
Intent,
|
||||
Switch,
|
||||
ToastPositionSetter,
|
||||
TradingButton,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { Switch, ToastPositionSetter } from '@vegaprotocol/ui-toolkit';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval';
|
||||
import { useState, type ReactNode } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
@@ -15,7 +9,6 @@ export const Settings = () => {
|
||||
const t = useT();
|
||||
const { theme, setTheme } = useThemeSwitcher();
|
||||
const [isApproved, setIsApproved] = useTelemetryApproval();
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<SettingsGroup label={t('Dark mode')}>
|
||||
@@ -40,52 +33,6 @@ export const Settings = () => {
|
||||
<SettingsGroup label={t('Toast location')}>
|
||||
<ToastPositionSetter />
|
||||
</SettingsGroup>
|
||||
<SettingsGroup label={t('Reset to default')}>
|
||||
<TradingButton
|
||||
name="reset-to-defaults"
|
||||
size="small"
|
||||
intent={Intent.None}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('Reset')}
|
||||
</TradingButton>
|
||||
<Dialog open={open} title={t('Reset')}>
|
||||
<div className="mb-4">
|
||||
<p>
|
||||
{t(
|
||||
'You will lose all persisted settings and you will be logged out.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{t('Are you sure you want to reset all settings to default?')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<TradingButton
|
||||
name="reset-to-defaults-cancel"
|
||||
intent={Intent.Primary}
|
||||
onClick={() => {
|
||||
localStorage.clear();
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
{t('Yes, clear cache and refresh')}
|
||||
</TradingButton>
|
||||
<TradingButton
|
||||
name="reset-to-defaults-cancel"
|
||||
intent={Intent.None}
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('No, keep settings')}
|
||||
</TradingButton>
|
||||
</div>
|
||||
</Dialog>
|
||||
</SettingsGroup>
|
||||
<SettingsGroup inline={false} label={t('App information')}>
|
||||
<dl className="text-sm grid grid-cols-2 gap-1">
|
||||
{process.env.GIT_TAG && (
|
||||
|
||||
@@ -44,5 +44,4 @@ def truncate_middle(market_id, start=6, end=4):
|
||||
def change_keys(page: Page, vega:VegaServiceNull, key_name):
|
||||
page.get_by_test_id("manage-vega-wallet").click()
|
||||
page.get_by_test_id("key-" + vega.wallet.public_key(key_name)).click()
|
||||
page.click(f'data-testid=key-{vega.wallet.public_key(key_name)} >> .inline-flex')
|
||||
page.reload()
|
||||
|
||||
@@ -136,11 +136,8 @@ def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRe
|
||||
page.add_init_script(script=window_env)
|
||||
yield page
|
||||
finally:
|
||||
try:
|
||||
if not os.path.exists("apps/trading/e2e/traces"):
|
||||
os.makedirs("apps/trading/e2e/traces")
|
||||
except OSError as e:
|
||||
print(f"Failed to create directory '{'apps/trading/e2e/traces'}': {e}")
|
||||
if not os.path.exists("traces"):
|
||||
os.makedirs("traces")
|
||||
|
||||
# Check whether this test failed or passed
|
||||
outcome = request.config.cache.get(request.node.nodeid, None)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import pytest
|
||||
from playwright.sync_api import expect, Page
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "risk_accepted")
|
||||
def test_see_market_depth_chart(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
# Click on the 'Depth' tab
|
||||
page.get_by_test_id("Depth").click()
|
||||
# Check if the 'Depth' tab and the depth chart are visible
|
||||
# 6006-DEPC-001
|
||||
expect(page.get_by_test_id("tab-depth")).to_be_visible()
|
||||
expect(page.locator('[class^="depth-chart-module_canvas__"]').first).to_be_visible()
|
||||
@@ -29,12 +29,11 @@ def continuous_market(vega):
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
|
||||
page.get_by_test_id(order_size).fill("10")
|
||||
page.get_by_test_id(order_price).fill("120")
|
||||
page.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
|
||||
expires_at = datetime.now() + timedelta(days=1)
|
||||
expires_at_input_value = expires_at.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
page.get_by_test_id("date-picker-field").clear()
|
||||
page.get_by_test_id("date-picker-field").fill(expires_at_input_value)
|
||||
# 7002-SORD-011
|
||||
expect(page.get_by_test_id("place-order").locator("span").first).to_have_text(
|
||||
|
||||
@@ -2,8 +2,10 @@ import pytest
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
from actions.vega import submit_order
|
||||
from conftest import init_vega
|
||||
from fixtures.market import setup_continuous_market
|
||||
from actions.utils import wait_for_toast_confirmation
|
||||
|
||||
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET, wallets
|
||||
|
||||
stop_order_btn = "order-type-Stop"
|
||||
stop_limit_order_btn = "order-type-StopLimit"
|
||||
@@ -326,4 +328,98 @@ def test_submit_stop_oco_limit_order_cancel(
|
||||
page.locator(".ag-center-cols-container").locator('[col-id="status"]').last
|
||||
).to_have_text("CancelledOCO")
|
||||
|
||||
class TestStopOcoValidation:
|
||||
@pytest.fixture(scope="class")
|
||||
def vega(self, request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def continuous_market(self, vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_stop_market_order_oco_form_validation(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_market_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_market_order_btn).click()
|
||||
page.get_by_test_id(oco).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
|
||||
).to_be_visible()
|
||||
# 7002-SORD-084
|
||||
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
# 7002-SORD-085
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
# 7002-SORD-087
|
||||
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-price"]')).to_be_checked
|
||||
# 7002-SORD-088
|
||||
expect(
|
||||
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
|
||||
).to_have_text("Trailing Percent Offset")
|
||||
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_stop_limit_order_oco_form_validation(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_market_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
page.get_by_test_id(oco).click()
|
||||
expect(
|
||||
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
|
||||
).to_be_visible()
|
||||
# 7002-SORD-099
|
||||
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
|
||||
"Rises above"
|
||||
)
|
||||
# 7002-SORD-091
|
||||
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
|
||||
"Falls below"
|
||||
)
|
||||
# 7002-SORD-095
|
||||
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
|
||||
expect(page.locator('[for="triggerType-price"]')).to_be_checked
|
||||
# 7002-SORD-095
|
||||
expect(
|
||||
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
|
||||
).to_have_text("Trailing Percent Offset")
|
||||
|
||||
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
|
||||
expect(page.locator('[for="order-price-oco"]')).to_have_text("Price")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_maximum_number_of_active_stop_orders_oco(
|
||||
self, continuous_market, vega: VegaService, page: Page
|
||||
):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id(stop_order_btn).click()
|
||||
page.get_by_test_id(stop_limit_order_btn).is_visible()
|
||||
page.get_by_test_id(stop_limit_order_btn).click()
|
||||
page.get_by_test_id(order_side_sell).click()
|
||||
page.locator("label").filter(has_text="Falls below").click()
|
||||
page.get_by_test_id(trigger_price).fill("102")
|
||||
page.get_by_test_id(order_size).fill("3")
|
||||
page.get_by_test_id(order_price).fill("103")
|
||||
page.get_by_test_id(oco).click()
|
||||
page.get_by_test_id(trigger_price_oco).fill("120")
|
||||
page.get_by_test_id(order_size_oco).fill("2")
|
||||
page.get_by_test_id(order_limit_price_oco).fill("99")
|
||||
for i in range(2):
|
||||
page.get_by_test_id(submit_stop_order).click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.wait_fn(1)
|
||||
vega.forward("20s")
|
||||
vega.wait_for_total_catchup()
|
||||
if page.get_by_test_id(close_toast).is_visible():
|
||||
page.get_by_test_id(close_toast).click()
|
||||
# 7002-SORD-011
|
||||
expect(page.get_by_test_id("stop-order-warning-limit")).to_have_text(
|
||||
"There is a limit of 4 active stop orders per market. Orders submitted above the limit will be immediately rejected."
|
||||
)
|
||||
|
||||
@@ -47,6 +47,48 @@ class TestIcebergOrdersValidations:
|
||||
(page.get_by_role("row").locator('[col-id="type"]')).nth(1)
|
||||
).to_have_text("Limit (Iceberg)")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_iceberg_tooltips(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("iceberg").hover()
|
||||
expect(page.get_by_role("tooltip")).to_be_visible()
|
||||
page.get_by_test_id("iceberg").click()
|
||||
hover_and_assert_tooltip(page, "Peak size")
|
||||
hover_and_assert_tooltip(page, "Minimum size")
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_iceberg_validations(self, continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
page.get_by_test_id("iceberg").click()
|
||||
page.get_by_test_id("place-order").click()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
|
||||
"You need to provide a peak size"
|
||||
)
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"You need to provide a minimum visible size"
|
||||
)
|
||||
page.get_by_test_id("order-peak-size").clear()
|
||||
page.get_by_test_id("order-peak-size").type("1")
|
||||
page.get_by_test_id("order-minimum-size").clear()
|
||||
page.get_by_test_id("order-minimum-size").type("2")
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
|
||||
"Peak size cannot be greater than the size (0)"
|
||||
)
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"Minimum visible size cannot be greater than the peak size (1)"
|
||||
)
|
||||
page.get_by_test_id("order-minimum-size").clear()
|
||||
page.get_by_test_id("order-minimum-size").type("0.1")
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
|
||||
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
|
||||
"Minimum visible size cannot be lower than 1"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import pytest
|
||||
import pytest
|
||||
import re
|
||||
from playwright.sync_api import Page, expect
|
||||
from vega_sim.service import VegaService
|
||||
@@ -20,23 +20,23 @@ def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
|
||||
# 1003-TRAN-010
|
||||
# 1003-TRAN-023
|
||||
page.goto('/#/portfolio')
|
||||
|
||||
|
||||
expect(page.get_by_test_id('transfer-form')).to_be_visible
|
||||
page.get_by_test_id('select-asset').click()
|
||||
expect(page.get_by_test_id('rich-select-option')).to_have_count(1)
|
||||
|
||||
|
||||
page.get_by_test_id('rich-select-option').click()
|
||||
page.select_option('[data-testid=transfer-form] [name="toVegaKey"]', index=2)
|
||||
page.select_option('[data-testid=transfer-form] [name="fromAccount"]', index=1)
|
||||
|
||||
expected_asset_text = re.compile(r"tDAI tDAI999991.49731 tDAI.{6}….{4}")
|
||||
|
||||
expected_asset_text = re.compile(r"tDAI tDAI999,991.49731 tDAI.{6}….{4}")
|
||||
actual_asset_text = page.get_by_test_id('select-asset').text_content().strip()
|
||||
|
||||
|
||||
assert expected_asset_text.search(actual_asset_text), f"Expected pattern not found in {actual_asset_text}"
|
||||
|
||||
|
||||
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('1')
|
||||
expect(page.locator('[data-testid=transfer-form] input[name="amount"]')).not_to_be_empty()
|
||||
|
||||
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
vega.forward("10s")
|
||||
@@ -45,15 +45,15 @@ def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}1\.00 tDAI")
|
||||
actual_confirmation_text = page.get_by_test_id('toast-content').text_content()
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
|
||||
def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, page: Page):
|
||||
vega.update_network_parameter(
|
||||
"market_maker", parameter="transfer.minTransferQuantumMultiple", new_value="100000"
|
||||
"market_maker", parameter="transfer.minTransferQuantumMultiple", new_value="100000"
|
||||
)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_A, amount=1e3)
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_B, amount=1e5)
|
||||
create_and_faucet_wallet(vega=vega, wallet=PARTY_C, amount=1e5)
|
||||
@@ -96,11 +96,11 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
|
||||
next_epoch(vega=vega)
|
||||
page.goto('/#/portfolio')
|
||||
expect(page.get_by_test_id('transfer-form')).to_be_visible
|
||||
|
||||
|
||||
change_keys(page, vega, "party_b")
|
||||
page.get_by_test_id('select-asset').click()
|
||||
page.get_by_test_id('rich-select-option').click()
|
||||
|
||||
|
||||
option_value = page.locator('[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]').first.get_attribute("value")
|
||||
|
||||
page.select_option('[data-testid="transfer-form"] [name="fromAccount"]', option_value)
|
||||
@@ -120,7 +120,7 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
|
||||
vega.forward("10s")
|
||||
vega.wait_fn(10)
|
||||
vega.wait_for_total_catchup()
|
||||
|
||||
|
||||
page.get_by_text("Use max").first.click()
|
||||
page.locator('[data-testid=transfer-form] [type="submit"]').click()
|
||||
wait_for_toast_confirmation(page)
|
||||
@@ -129,4 +129,4 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
|
||||
vega.wait_for_total_catchup()
|
||||
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmedView in block explorerTransferTo .{6}….{6}0\.00001 tDAI")
|
||||
actual_confirmation_text = page.get_by_test_id('toast-content').text_content()
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
|
||||
@@ -1,23 +1,10 @@
|
||||
import { act, render, screen, within } from '@testing-library/react';
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import type { AccountFields } from './accounts-data-provider';
|
||||
import { getAccountData } from './accounts-data-provider';
|
||||
import { AccountTable } from './accounts-table';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
const asset1 = {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-1',
|
||||
symbol: 'tBTC',
|
||||
decimals: 5,
|
||||
name: 'T BTC',
|
||||
};
|
||||
const asset2 = {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-2',
|
||||
symbol: 'aBTC',
|
||||
decimals: 5,
|
||||
name: 'A BTC',
|
||||
};
|
||||
|
||||
const singleRow = {
|
||||
__typename: 'AccountBalance',
|
||||
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
@@ -26,7 +13,12 @@ const singleRow = {
|
||||
__typename: 'Market',
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
},
|
||||
asset: asset1,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
decimals: 5,
|
||||
},
|
||||
available: '125600000',
|
||||
used: '125600000',
|
||||
total: '251200000',
|
||||
@@ -41,7 +33,12 @@ const secondRow = {
|
||||
__typename: 'Market',
|
||||
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
|
||||
},
|
||||
asset: asset2,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'aBTC',
|
||||
decimals: 5,
|
||||
},
|
||||
available: '125600001',
|
||||
used: '125600001',
|
||||
total: '251200002',
|
||||
@@ -137,7 +134,7 @@ describe('AccountsTable', () => {
|
||||
|
||||
it('should sort assets', async () => {
|
||||
// 7001-COLL-010
|
||||
render(
|
||||
const { container } = render(
|
||||
<AccountTable
|
||||
rowData={multiRowData}
|
||||
onClickAsset={() => null}
|
||||
@@ -145,13 +142,13 @@ describe('AccountsTable', () => {
|
||||
/>
|
||||
);
|
||||
|
||||
const headerCell = screen
|
||||
.getAllByRole('columnheader')
|
||||
.find((h) => h?.getAttribute('col-id') === 'asset.symbol') as HTMLElement;
|
||||
|
||||
await userEvent.click(within(headerCell).getByText(/asset/i));
|
||||
|
||||
expect(headerCell).toHaveAttribute('aria-sort', 'ascending');
|
||||
const headerCell = screen.getByText('Asset');
|
||||
await userEvent.click(headerCell);
|
||||
const rows = container.querySelectorAll(
|
||||
'.ag-center-cols-container .ag-row'
|
||||
);
|
||||
expect(rows[0].textContent).toContain('aBTC');
|
||||
expect(rows[1].textContent).toContain('tBTC');
|
||||
});
|
||||
|
||||
it('should apply correct formatting in view as user mode', async () => {
|
||||
@@ -179,7 +176,12 @@ describe('AccountsTable', () => {
|
||||
rowData={singleRowData}
|
||||
onClickAsset={() => null}
|
||||
isReadOnly={false}
|
||||
pinnedAsset={asset1}
|
||||
pinnedAsset={{
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
name: 'tBTC',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
await screen.findAllByRole('rowgroup');
|
||||
@@ -211,13 +213,23 @@ describe('AccountsTable', () => {
|
||||
const result = getAccountData([singleRow]);
|
||||
const expected = [
|
||||
{
|
||||
asset: asset1,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
},
|
||||
available: '0',
|
||||
balance: '0',
|
||||
breakdown: [
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
asset: asset1,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
decimals: 5,
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
},
|
||||
available: '0',
|
||||
balance: '125600000',
|
||||
total: '125600000',
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from '@testing-library/react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {
|
||||
@@ -13,7 +7,7 @@ import {
|
||||
TransferForm,
|
||||
type TransferFormProps,
|
||||
} from './transfer-form';
|
||||
import { AccountType, AccountTypeMapping } from '@vegaprotocol/types';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
|
||||
describe('TransferForm', () => {
|
||||
@@ -45,7 +39,8 @@ describe('TransferForm', () => {
|
||||
};
|
||||
|
||||
const amount = '100';
|
||||
const pubKey = '1'.repeat(64);
|
||||
const pubKey =
|
||||
'70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680';
|
||||
const asset = {
|
||||
id: 'eur',
|
||||
symbol: '€',
|
||||
@@ -55,7 +50,10 @@ describe('TransferForm', () => {
|
||||
};
|
||||
const props = {
|
||||
pubKey,
|
||||
pubKeys: [pubKey, '2'.repeat(64)],
|
||||
pubKeys: [
|
||||
pubKey,
|
||||
'a4b6e3de5d7ef4e31ae1b090be49d1a2ef7bcefff60cccf7658a0d4922651cce',
|
||||
],
|
||||
feeFactor: '0.001',
|
||||
submitTransfer: jest.fn(),
|
||||
accounts: [
|
||||
@@ -179,7 +177,7 @@ describe('TransferForm', () => {
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue('1000.00');
|
||||
expect(amountInput).toHaveValue('1000');
|
||||
|
||||
// Test amount validation
|
||||
await userEvent.clear(amountInput);
|
||||
@@ -264,7 +262,7 @@ describe('TransferForm', () => {
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue('100.00');
|
||||
expect(amountInput).toHaveValue('100');
|
||||
|
||||
// If transfering from a vested account 'include fees' checkbox should
|
||||
// be disabled and fees should be 0
|
||||
@@ -293,88 +291,6 @@ describe('TransferForm', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('handles lots of decimal places', async () => {
|
||||
const balance = '904195168829277777';
|
||||
const expectedBalance = '0.904195168829277777';
|
||||
|
||||
const longDecimalAsset = {
|
||||
id: 'assetId',
|
||||
symbol: 'VEGA',
|
||||
name: 'VEGA',
|
||||
decimals: 18,
|
||||
quantum: '1',
|
||||
};
|
||||
|
||||
const account = {
|
||||
type: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||
asset: longDecimalAsset,
|
||||
balance,
|
||||
};
|
||||
|
||||
const mockSubmit = jest.fn();
|
||||
|
||||
renderComponent({
|
||||
...props,
|
||||
accounts: [account],
|
||||
submitTransfer: mockSubmit,
|
||||
minQuantumMultiple: '100000',
|
||||
});
|
||||
|
||||
// Select a pubkey
|
||||
await userEvent.selectOptions(
|
||||
screen.getByLabelText('To Vega key'),
|
||||
props.pubKeys[1] // Use not current pubkey so we can check it switches to current pubkey later
|
||||
);
|
||||
|
||||
// Select asset
|
||||
await selectAsset(longDecimalAsset);
|
||||
|
||||
const accountSelect = screen.getByLabelText('From account');
|
||||
const option = within(accountSelect)
|
||||
.getAllByRole('option')
|
||||
.find(
|
||||
(o) => o.getAttribute('value') === `${account.type}-${account.asset.id}`
|
||||
);
|
||||
// plus one for disabled 'please select' option
|
||||
|
||||
expect(option).toHaveTextContent(
|
||||
`${AccountTypeMapping[account.type]} (${expectedBalance} ${
|
||||
account.asset.symbol
|
||||
})`
|
||||
);
|
||||
|
||||
await userEvent.selectOptions(
|
||||
accountSelect,
|
||||
`${AccountType.ACCOUNT_TYPE_VESTED_REWARDS}-${longDecimalAsset.id}`
|
||||
);
|
||||
|
||||
expect(accountSelect).toHaveValue(
|
||||
`${AccountType.ACCOUNT_TYPE_VESTED_REWARDS}-${longDecimalAsset.id}`
|
||||
);
|
||||
|
||||
// Check switch back to connected key
|
||||
const amountInput = screen.getByLabelText('Amount');
|
||||
|
||||
// Test use max button
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Use max' }));
|
||||
expect(amountInput).toHaveValue(expectedBalance);
|
||||
|
||||
await submit();
|
||||
|
||||
await waitFor(() => {
|
||||
// 1003-TRAN-023
|
||||
expect(mockSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(mockSubmit).toHaveBeenCalledWith({
|
||||
fromAccountType: AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
to: props.pubKey,
|
||||
asset: longDecimalAsset.id,
|
||||
amount: balance,
|
||||
oneOff: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('IncludeFeesCheckbox', () => {
|
||||
it('validates fields and submits when checkbox is checked', async () => {
|
||||
const mockSubmit = jest.fn();
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
useVegaPublicKey,
|
||||
addDecimal,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { useT } from './use-t';
|
||||
@@ -217,7 +218,12 @@ export const TransferForm = ({
|
||||
<AssetOption
|
||||
key={a.key}
|
||||
asset={a}
|
||||
balance={<Balance balance={a.balance} symbol={a.symbol} />}
|
||||
balance={
|
||||
<Balance
|
||||
balance={formatNumber(a.balance, a.decimals)}
|
||||
symbol={a.symbol}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TradingRichSelect>
|
||||
@@ -284,8 +290,8 @@ export const TransferForm = ({
|
||||
return (
|
||||
<option value={id} key={id}>
|
||||
{AccountTypeMapping[a.type]} (
|
||||
{addDecimal(a.balance, a.asset.decimals)} {a.asset.symbol}
|
||||
)
|
||||
{addDecimalsFormatNumber(a.balance, a.asset.decimals)}{' '}
|
||||
{a.asset.symbol})
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
@@ -414,7 +420,7 @@ export const TransferForm = ({
|
||||
type="button"
|
||||
className="absolute right-0 top-0 ml-auto text-xs underline"
|
||||
onClick={() =>
|
||||
setValue('amount', accountBalance, {
|
||||
setValue('amount', parseFloat(accountBalance).toString(), {
|
||||
shouldValidate: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { getAsset, getQuoteName } from '@vegaprotocol/markets';
|
||||
import { getAsset, getProductType, getQuoteName } from '@vegaprotocol/markets';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
|
||||
@@ -297,120 +297,134 @@ export const DealTicketMarginDetails = ({
|
||||
);
|
||||
|
||||
const quoteName = getQuoteName(market);
|
||||
const productType = getProductType(market);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full gap-2 pt-2">
|
||||
<Accordion>
|
||||
<AccordionPanel
|
||||
itemId="margin"
|
||||
trigger={
|
||||
<AccordionPrimitive.Trigger
|
||||
data-testid="accordion-toggle"
|
||||
className={classNames(
|
||||
'w-full',
|
||||
'flex items-center gap-2 text-xs',
|
||||
'group'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
data-testid={`deal-ticket-fee-margin-required`}
|
||||
key={'value-dropdown'}
|
||||
className="flex items-center justify-between w-full gap-2"
|
||||
>
|
||||
<div className="flex items-center text-left gap-1">
|
||||
<Tooltip
|
||||
description={t(
|
||||
'MARGIN_DIFF_TOOLTIP_TEXT',
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
{ assetSymbol }
|
||||
)}
|
||||
>
|
||||
<span className="text-muted">{t('Margin required')}</span>
|
||||
</Tooltip>
|
||||
{/*
|
||||
TODO: remove this conditional check once the following PRs are deployed
|
||||
and the estimatePosition query is working for perps
|
||||
|
||||
<AccordionChevron size={10} />
|
||||
</div>
|
||||
<Tooltip
|
||||
description={
|
||||
formatRange(
|
||||
marginRequiredBestCase,
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals
|
||||
) ?? '-'
|
||||
}
|
||||
- https://github.com/vegaprotocol/vega/pull/10119
|
||||
- https://github.com/vegaprotocol/vega/pull/10122
|
||||
*/}
|
||||
{productType === 'Future' && (
|
||||
<>
|
||||
<Accordion>
|
||||
<AccordionPanel
|
||||
itemId="margin"
|
||||
trigger={
|
||||
<AccordionPrimitive.Trigger
|
||||
data-testid="accordion-toggle"
|
||||
className={classNames(
|
||||
'w-full',
|
||||
'flex items-center gap-2 text-xs',
|
||||
'group'
|
||||
)}
|
||||
>
|
||||
<div className="font-mono text-right">
|
||||
{formatValue(
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}{' '}
|
||||
{assetSymbol || ''}
|
||||
<div
|
||||
data-testid={`deal-ticket-fee-margin-required`}
|
||||
key={'value-dropdown'}
|
||||
className="flex items-center justify-between w-full gap-2"
|
||||
>
|
||||
<div className="flex items-center text-left gap-1">
|
||||
<Tooltip
|
||||
description={t(
|
||||
'MARGIN_DIFF_TOOLTIP_TEXT',
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
{ assetSymbol }
|
||||
)}
|
||||
>
|
||||
<span className="text-muted">
|
||||
{t('Margin required')}
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
<AccordionChevron size={10} />
|
||||
</div>
|
||||
<Tooltip
|
||||
description={
|
||||
formatRange(
|
||||
marginRequiredBestCase,
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals
|
||||
) ?? '-'
|
||||
}
|
||||
>
|
||||
<div className="font-mono text-right">
|
||||
{formatValue(
|
||||
marginRequiredWorstCase,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}{' '}
|
||||
{assetSymbol || ''}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</AccordionPrimitive.Trigger>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<KeyValue
|
||||
label={t('Total margin available')}
|
||||
indent
|
||||
value={formatValue(totalMarginAvailable, assetDecimals)}
|
||||
formattedValue={formatValue(
|
||||
totalMarginAvailable,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'TOTAL_MARGIN_AVAILABLE',
|
||||
TOTAL_MARGIN_AVAILABLE,
|
||||
{
|
||||
generalAccountBalance: formatValue(
|
||||
generalAccountBalance,
|
||||
</AccordionPrimitive.Trigger>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<KeyValue
|
||||
label={t('Total margin available')}
|
||||
indent
|
||||
value={formatValue(totalMarginAvailable, assetDecimals)}
|
||||
formattedValue={formatValue(
|
||||
totalMarginAvailable,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginAccountBalance: formatValue(
|
||||
)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'TOTAL_MARGIN_AVAILABLE',
|
||||
TOTAL_MARGIN_AVAILABLE,
|
||||
{
|
||||
generalAccountBalance: formatValue(
|
||||
generalAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginAccountBalance: formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginMaintenance: formatValue(
|
||||
currentMargins?.maintenanceLevel,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
assetSymbol,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
{deductionFromCollateral}
|
||||
<KeyValue
|
||||
label={t('Current margin allocation')}
|
||||
indent
|
||||
onClick={
|
||||
generalAccountBalance
|
||||
? () => setBreakdownDialog(true)
|
||||
: undefined
|
||||
}
|
||||
value={formatValue(marginAccountBalance, assetDecimals)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'MARGIN_ACCOUNT_TOOLTIP_TEXT',
|
||||
MARGIN_ACCOUNT_TOOLTIP_TEXT
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
marginMaintenance: formatValue(
|
||||
currentMargins?.maintenanceLevel,
|
||||
assetDecimals,
|
||||
quantum
|
||||
),
|
||||
assetSymbol,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
{deductionFromCollateral}
|
||||
<KeyValue
|
||||
label={t('Current margin allocation')}
|
||||
indent
|
||||
onClick={
|
||||
generalAccountBalance
|
||||
? () => setBreakdownDialog(true)
|
||||
: undefined
|
||||
}
|
||||
value={formatValue(marginAccountBalance, assetDecimals)}
|
||||
symbol={assetSymbol}
|
||||
labelDescription={t(
|
||||
'MARGIN_ACCOUNT_TOOLTIP_TEXT',
|
||||
MARGIN_ACCOUNT_TOOLTIP_TEXT
|
||||
)}
|
||||
formattedValue={formatValue(
|
||||
marginAccountBalance,
|
||||
assetDecimals,
|
||||
quantum
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</Accordion>
|
||||
{projectedMargin}
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</Accordion>
|
||||
{projectedMargin}
|
||||
</>
|
||||
)}
|
||||
<KeyValue
|
||||
label={t('Liquidation')}
|
||||
value={liquidationPriceEstimateRange}
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('StopOrder', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should display ticket defaults limit order', async () => {
|
||||
it('should display ticket defaults', async () => {
|
||||
render(generateJsx());
|
||||
// place order button should always be enabled
|
||||
expect(screen.getByTestId(submitButton)).toBeEnabled();
|
||||
@@ -131,47 +131,6 @@ describe('StopOrder', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should display ticket defaults market order', async () => {
|
||||
render(generateJsx());
|
||||
// place order button should always be enabled
|
||||
expect(screen.getByTestId(submitButton)).toBeEnabled();
|
||||
// Assert defaults are used
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
expect(screen.getByTestId(orderTypeLimit).dataset.state).toEqual(
|
||||
'unchecked'
|
||||
);
|
||||
expect(screen.getByTestId(orderTypeMarket).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
expect(screen.getByTestId(orderSideBuy).dataset.state).toEqual('checked');
|
||||
expect(screen.getByTestId(sizeInput)).toHaveDisplayValue('0');
|
||||
expect(screen.getByTestId(timeInForce)).toHaveValue(
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK
|
||||
);
|
||||
// 7002-SORD-084
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionRisesAbove).dataset.state
|
||||
).toEqual('checked');
|
||||
// 7002-SORD-085
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionFallsBelow).dataset.state
|
||||
).toEqual('unchecked');
|
||||
expect(screen.getByTestId(triggerTypePrice).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
expect(screen.getByTestId(expire).dataset.state).toEqual('unchecked');
|
||||
expect(screen.getByTestId(oco).dataset.state).toEqual('unchecked');
|
||||
await userEvent.click(screen.getByTestId(expire));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(expiryStrategySubmit).dataset.state).toEqual(
|
||||
'checked'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('calculate notional for market limit', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '10');
|
||||
@@ -280,43 +239,33 @@ describe('StopOrder', () => {
|
||||
it.each([
|
||||
{ fieldName: 'size', ocoValue: false },
|
||||
{ fieldName: 'ocoSize', ocoValue: true },
|
||||
{ fieldName: 'size', ocoValue: false, orderTypeMarketValue: true },
|
||||
{ fieldName: 'ocoSize', ocoValue: true, orderTypeMarketValue: true },
|
||||
])(
|
||||
'validates $fieldName field',
|
||||
async ({ ocoValue, orderTypeMarketValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarketValue) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// default value should be invalid
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(sizeInput), '0.01');
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using valid value
|
||||
await userEvent.clear(getByTestId(sizeInput));
|
||||
await userEvent.type(getByTestId(sizeInput), '0.1');
|
||||
expect(queryByTestId(sizeErrorMessage)).toBeNull();
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
);
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// default value should be invalid
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(sizeInput), '0.01');
|
||||
expect(getByTestId(sizeErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using valid value
|
||||
await userEvent.clear(getByTestId(sizeInput));
|
||||
await userEvent.type(getByTestId(sizeInput), '0.1');
|
||||
expect(queryByTestId(sizeErrorMessage)).toBeNull();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ fieldName: 'price', ocoValue: false },
|
||||
{ fieldName: 'ocoPrice', ocoValue: true },
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
@@ -326,7 +275,7 @@ describe('StopOrder', () => {
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// 7002-SORD-095
|
||||
|
||||
expect(getByTestId(priceErrorMessage)).toBeInTheDocument();
|
||||
await userEvent.type(getByTestId(priceInput), '0.001');
|
||||
expect(getByTestId(priceErrorMessage)).toBeInTheDocument();
|
||||
@@ -356,77 +305,48 @@ describe('StopOrder', () => {
|
||||
it.each([
|
||||
{ fieldName: 'triggerPrice', ocoValue: false },
|
||||
{ fieldName: 'ocoTriggerPrice', ocoValue: true },
|
||||
{ fieldName: 'triggerPrice', ocoValue: false, orderTypeMarketValue: true },
|
||||
{
|
||||
fieldName: 'ocoTriggerPrice',
|
||||
ocoValue: true,
|
||||
orderTypeMarketValue: true,
|
||||
},
|
||||
])(
|
||||
'validates $fieldName field',
|
||||
async ({ ocoValue, orderTypeMarketValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarketValue) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
await userEvent.click(screen.getByTestId(triggerDirectionFallsBelow));
|
||||
}
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
// 7002-SORD-095
|
||||
// 7002-SORD-087
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// switch to trailing percentage offset trigger type
|
||||
await userEvent.click(getByTestId(triggerTypeTrailingPercentOffset));
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
|
||||
// switch back to price trigger type
|
||||
await userEvent.click(getByTestId(triggerTypePrice));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.001');
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using value causing immediate trigger
|
||||
await userEvent.clear(getByTestId(triggerPriceInput));
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.01');
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeInTheDocument();
|
||||
|
||||
// change to correct value
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '2');
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeNull();
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
await userEvent.click(screen.getByTestId(triggerDirectionFallsBelow));
|
||||
}
|
||||
);
|
||||
await userEvent.click(screen.getByTestId(submitButton));
|
||||
const getByTestId = (id: string) =>
|
||||
screen.getByTestId(ocoPostfix(id, ocoValue));
|
||||
const queryByTestId = (id: string) =>
|
||||
screen.queryByTestId(ocoPostfix(id, ocoValue));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// switch to trailing percentage offset trigger type
|
||||
await userEvent.click(getByTestId(triggerTypeTrailingPercentOffset));
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
|
||||
// switch back to price trigger type
|
||||
await userEvent.click(getByTestId(triggerTypePrice));
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// to small value should be invalid
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.001');
|
||||
expect(getByTestId(triggerPriceErrorMessage)).toBeInTheDocument();
|
||||
|
||||
// clear and fill using value causing immediate trigger
|
||||
await userEvent.clear(getByTestId(triggerPriceInput));
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '0.01');
|
||||
expect(queryByTestId(triggerPriceErrorMessage)).toBeNull();
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeInTheDocument();
|
||||
|
||||
// change to correct value
|
||||
await userEvent.type(getByTestId(triggerPriceInput), '2');
|
||||
expect(queryByTestId(triggerPriceWarningMessage)).toBeNull();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ fieldName: 'trailingPercentageOffset', ocoValue: false },
|
||||
{ fieldName: 'ocoTrailingPercentageOffset', ocoValue: true },
|
||||
{
|
||||
fieldName: 'trailingPercentageOffset',
|
||||
ocoValue: false,
|
||||
orderTypeMarket: true,
|
||||
},
|
||||
{
|
||||
fieldName: 'ocoTrailingPercentageOffset',
|
||||
ocoValue: true,
|
||||
orderTypeMarket: true,
|
||||
},
|
||||
])('validates $fieldName field', async ({ ocoValue }) => {
|
||||
render(generateJsx());
|
||||
if (orderTypeMarket) {
|
||||
await userEvent.click(screen.getByTestId(orderTypeTrigger));
|
||||
await userEvent.click(screen.getByTestId(orderTypeMarket));
|
||||
}
|
||||
if (ocoValue) {
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
}
|
||||
@@ -481,11 +401,9 @@ describe('StopOrder', () => {
|
||||
it('sync oco trigger', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId(oco));
|
||||
// 7002-SORD-099
|
||||
expect(
|
||||
screen.getByTestId(triggerDirectionRisesAbove).dataset.state
|
||||
).toEqual('checked');
|
||||
// 7002-SORD-091
|
||||
expect(
|
||||
screen.getByTestId(ocoPostfix(triggerDirectionFallsBelow)).dataset.state
|
||||
).toEqual('checked');
|
||||
@@ -563,7 +481,6 @@ describe('StopOrder', () => {
|
||||
expect(mockDataProvider.mock.lastCall?.[0].skip).toBe(true);
|
||||
await userEvent.type(screen.getByTestId(sizeInput), '0.01');
|
||||
expect(mockDataProvider.mock.lastCall?.[0].skip).toBe(false);
|
||||
// 7002-SORD-011
|
||||
expect(screen.getByTestId(numberOfActiveOrdersLimit)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -367,29 +367,6 @@ describe('DealTicket', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should see an explanation of peak size', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId('iceberg'));
|
||||
await userEvent.hover(screen.getByText('Peak size'));
|
||||
await waitFor(() => {
|
||||
const tooltips = screen.getAllByTestId('tooltip-content');
|
||||
expect(tooltips[0]).toHaveTextContent(
|
||||
`The maximum volume that can be traded at once. Must be less than the total size of the order.`
|
||||
);
|
||||
});
|
||||
});
|
||||
it('should see an explanation of minimum size', async () => {
|
||||
render(generateJsx());
|
||||
await userEvent.click(screen.getByTestId('iceberg'));
|
||||
await userEvent.hover(screen.getByText('Minimum size'));
|
||||
await waitFor(() => {
|
||||
const tooltips = screen.getAllByTestId('tooltip-content');
|
||||
expect(tooltips[0]).toHaveTextContent(
|
||||
`When the order trades and its size falls below this threshold, it will be reset to the peak size and moved to the back of the priority order. Must be less than or equal to peak size, and greater than 0.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should see an explanation of reduce only', async () => {
|
||||
render(generateJsx());
|
||||
userEvent.hover(screen.getByText('Reduce only'));
|
||||
|
||||
@@ -85,7 +85,6 @@ export const DocsLinks = VEGA_DOCS_URL
|
||||
ICEBERG_ORDERS: `${VEGA_DOCS_URL}/concepts/trading-on-vega/orders#iceberg-order`,
|
||||
POST_REDUCE_ONLY: `${VEGA_DOCS_URL}/concepts/trading-on-vega/orders#conditional-order-parameters`,
|
||||
QUANTUM: `${VEGA_DOCS_URL}/concepts/assets/asset-framework#quantum`,
|
||||
REFERRALS: `${VEGA_DOCS_URL}/tutorials/proposals/referral-program-proposal`,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ describe('DepthChart', () => {
|
||||
<DepthChartContainer marketId={'market-id'} />
|
||||
</MockedProvider>
|
||||
);
|
||||
// 6006-DEPC-001
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,17 +6,14 @@ import { MockedProvider } from '@apollo/client/testing';
|
||||
import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
|
||||
const mockCreate = jest.fn();
|
||||
|
||||
jest.mock('@vegaprotocol/wallet', () => ({
|
||||
...jest.requireActual('@vegaprotocol/wallet'),
|
||||
useVegaWallet: jest.fn(() => ({ pubKey: 'partyId' })),
|
||||
}));
|
||||
|
||||
jest.mock('@vegaprotocol/web3', () => ({
|
||||
...jest.requireActual('@vegaprotocol/web3'),
|
||||
useVegaTransactionStore: jest.fn(() => mockCreate),
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const mockUseDataProvider = (args: any) => {
|
||||
if (args.dataProvider === positionsMarketsProvider) {
|
||||
@@ -24,20 +21,17 @@ const mockUseDataProvider = (args: any) => {
|
||||
}
|
||||
return { data: [singleRow] };
|
||||
};
|
||||
|
||||
jest.mock('@vegaprotocol/data-provider', () => ({
|
||||
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||
useDataProvider: jest.fn((args) => mockUseDataProvider(args)),
|
||||
}));
|
||||
|
||||
describe('PositionsManager', () => {
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('should close position with max uint64', async () => {
|
||||
it('should close position with max uint64', async () => {
|
||||
render(<PositionsManager partyIds={['partyId']} isReadOnly={false} />, {
|
||||
wrapper: MockedProvider,
|
||||
});
|
||||
expect(await screen.findByTestId('close-position')).toBeInTheDocument();
|
||||
expect(await screen.getByTestId('close-position')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByTestId('close-position'));
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import { PositionsTable } from './positions-table';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import {
|
||||
@@ -6,15 +9,9 @@ import {
|
||||
positionsMarketsProvider,
|
||||
} from './positions-data-providers';
|
||||
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
|
||||
import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
import { useT } from '../use-t';
|
||||
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
//
|
||||
// import { useCallback } from 'react';
|
||||
// import * as Schema from '@vegaprotocol/types';
|
||||
// import { useVegaTransactionStore } from '@vegaprotocol/web3';
|
||||
// import { MAXGOINT64 } from '@vegaprotocol/utils';
|
||||
|
||||
interface PositionsManagerProps {
|
||||
partyIds: string[];
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
@@ -32,37 +29,33 @@ export const PositionsManager = ({
|
||||
}: PositionsManagerProps) => {
|
||||
const t = useT();
|
||||
const { pubKeys, pubKey } = useVegaWallet();
|
||||
|
||||
// TODO: Close position temporarily disabled in https://github.com/vegaprotocol/frontend-monorepo/pull/5350
|
||||
//
|
||||
// const create = useVegaTransactionStore((store) => store.create);
|
||||
//
|
||||
// const onClose = useCallback(
|
||||
// ({ marketId, openVolume }: { marketId: string; openVolume: string }) =>
|
||||
// create({
|
||||
// batchMarketInstructions: {
|
||||
// cancellations: [
|
||||
// {
|
||||
// marketId,
|
||||
// orderId: '', // omit order id to cancel all active orders
|
||||
// },
|
||||
// ],
|
||||
// submissions: [
|
||||
// {
|
||||
// marketId: marketId,
|
||||
// type: Schema.OrderType.TYPE_MARKET as const,
|
||||
// timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC as const,
|
||||
// side: openVolume.startsWith('-')
|
||||
// ? Schema.Side.SIDE_BUY
|
||||
// : Schema.Side.SIDE_SELL,
|
||||
// size: MAXGOINT64, // improvement for avoiding leftovers filled in the meantime when close request has been sent
|
||||
// reduceOnly: true,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
// [create]
|
||||
// );
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
const onClose = useCallback(
|
||||
({ marketId, openVolume }: { marketId: string; openVolume: string }) =>
|
||||
create({
|
||||
batchMarketInstructions: {
|
||||
cancellations: [
|
||||
{
|
||||
marketId,
|
||||
orderId: '', // omit order id to cancel all active orders
|
||||
},
|
||||
],
|
||||
submissions: [
|
||||
{
|
||||
marketId: marketId,
|
||||
type: Schema.OrderType.TYPE_MARKET as const,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC as const,
|
||||
side: openVolume.startsWith('-')
|
||||
? Schema.Side.SIDE_BUY
|
||||
: Schema.Side.SIDE_SELL,
|
||||
size: MAXGOINT64, // improvement for avoiding leftovers filled in the meantime when close request has been sent
|
||||
reduceOnly: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
[create]
|
||||
);
|
||||
|
||||
const { data: marketIds } = useDataProvider({
|
||||
dataProvider: positionsMarketsProvider,
|
||||
@@ -81,8 +74,7 @@ export const PositionsManager = ({
|
||||
pubKeys={pubKeys}
|
||||
rowData={data}
|
||||
onMarketClick={onMarketClick}
|
||||
// TODO: temporarily disable close position
|
||||
// onClose={onClose}
|
||||
onClose={onClose}
|
||||
isReadOnly={isReadOnly}
|
||||
multipleKeys={partyIds.length > 1}
|
||||
overlayNoRowsTemplate={error ? error.message : t('No positions')}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { useVegaWallet } from '../use-vega-wallet';
|
||||
import { useChainId } from './use-chain-id';
|
||||
|
||||
global.fetch = jest.fn();
|
||||
const mockFetch = global.fetch as jest.Mock;
|
||||
mockFetch.mockImplementation((url: string) => {
|
||||
return Promise.resolve({ ok: true });
|
||||
});
|
||||
|
||||
jest.mock('../use-vega-wallet', () => {
|
||||
const original = jest.requireActual('../use-vega-wallet');
|
||||
return {
|
||||
...original,
|
||||
useVegaWallet: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('useChainId', () => {
|
||||
it('does not call fetch when statistics url could not be determined', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: '',
|
||||
});
|
||||
renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(mockFetch).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls fetch with correct statistics url', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'http://localhost:1234/statistics'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not return chain id when chain id is not present in response', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
const { result } = renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns chain id when chain id is present in response', async () => {
|
||||
(useVegaWallet as jest.Mock).mockReturnValue({
|
||||
vegaUrl: 'http://localhost:1234/graphql',
|
||||
});
|
||||
mockFetch.mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => ({
|
||||
statistics: {
|
||||
chainId: '1234',
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
const { result } = renderHook(() => useChainId());
|
||||
await waitFor(() => {
|
||||
expect(result.current).not.toBeUndefined();
|
||||
expect(result.current).toEqual('1234');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,37 +3,17 @@ import { useVegaWallet } from '../use-vega-wallet';
|
||||
|
||||
const cache: Record<string, string> = {};
|
||||
|
||||
/**
|
||||
* Gets the statistics url for a given vega url.
|
||||
* Example:
|
||||
* https://graphql.example.com/graphql -> https://graphql.example.com/statistics
|
||||
*/
|
||||
const getNodeStatisticsUrl = (vegaUrl: string) => {
|
||||
try {
|
||||
const url = new URL(vegaUrl);
|
||||
url.pathname = 'statistics';
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const useChainId = () => {
|
||||
const { vegaUrl } = useVegaWallet();
|
||||
const [chainId, setChainId] = useState<undefined | string>(cache[vegaUrl]);
|
||||
const [fetchAttempt, setFetchAttempt] = useState(1);
|
||||
|
||||
const statisticsUrl = getNodeStatisticsUrl(vegaUrl);
|
||||
|
||||
useEffect(() => {
|
||||
// abort when `/statistics` URL could not be determined
|
||||
if (!statisticsUrl) return;
|
||||
let isCancelled = false;
|
||||
if (cache[vegaUrl]) {
|
||||
setChainId(cache[vegaUrl]);
|
||||
return;
|
||||
}
|
||||
fetch(statisticsUrl)
|
||||
fetch(vegaUrl.replace('graphql', 'statistics'))
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
if (isCancelled) {
|
||||
@@ -52,6 +32,6 @@ export const useChainId = () => {
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [fetchAttempt, statisticsUrl, vegaUrl]);
|
||||
}, [fetchAttempt, vegaUrl]);
|
||||
return chainId;
|
||||
};
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@
|
||||
"jsondiffpatch": "^0.4.1",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "13.3.0",
|
||||
"pennant": "^1.15.0",
|
||||
"pennant": "^1.14.1",
|
||||
"react": "18.2.0",
|
||||
"react-copy-to-clipboard": "5.1.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
||||
@@ -17884,10 +17884,10 @@ pend@~1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
|
||||
|
||||
pennant@^1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.15.0.tgz#21854cf78466cbd27eda8143c21abcde070d4d76"
|
||||
integrity sha512-p3H4vu6BP7nUqn7s2pjyTl0FMJUT2U5lq5UKuxy55F2E66sJnvp5XFvNjRZvi42vyzsxG8WURgwQDQKNqQgWAw==
|
||||
pennant@^1.14.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.14.1.tgz#8e7a53256095e398b03397af31c831b02a56032b"
|
||||
integrity sha512-rjzo/tlFanO96OKhJiyjQtjug7sY6pjVZqVbieD3Tf4zt20bqIb6m4L2JfwOXEe0jqP/yddgCNPY+vlkVuJW1Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@d3fc/d3fc-technical-indicator" "^8.0.1"
|
||||
|
||||
Reference in New Issue
Block a user