Compare commits

..
69 changed files with 1634 additions and 412 deletions
+1
View File
@@ -1,3 +1,4 @@
* text eol=lf
*.png binary
*.ico binary
*.woff2 binary
@@ -54,7 +54,7 @@ const Block = () => {
</Button>
</Link>
</div>
{blockData && 'result' in blockData && (
{blockData && (
<>
<TableWithTbody className="mb-8">
<TableRow modifier="bordered">
@@ -95,7 +95,7 @@ export const ProtocolUpgradeProposalContainer = () => {
time={
pending && time ? (
convertToCountdownString(time, '0:00:00:00')
) : blockInfo && 'result' in blockInfo && blockInfo?.result ? (
) : blockInfo?.result ? (
<span title={blockInfo.result.block.header.time}>
{formatDateWithLocalTimezone(
new Date(blockInfo.result.block.header.time)
@@ -2,6 +2,7 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useCallback } from 'react';
import { useRefereesQuery } from './__generated__/Referees';
import compact from 'lodash/compact';
import pick from 'lodash/pick';
import type {
ReferralSetsQuery,
ReferralSetsQueryVariables,
@@ -122,6 +123,66 @@ export const useReferral = (args: UseReferralArgs) => {
};
};
type Referee = NonNullable<
NonNullable<ReturnType<typeof useReferral>['data']>['referee']
>;
type RefereeProperties = (keyof Referee)[];
const findReferee = (referee: Referee, referees: Referee[]) =>
referees.find((r) => r.refereeId === referee?.refereeId) || referee;
const updateReferee = (
referee: Referee,
referees: Referee[],
properties: RefereeProperties
) => ({
...referee,
...pick(findReferee(referee, referees), properties),
});
export const useUpdateReferees = (
referral: ReturnType<typeof useReferral>,
aggregationEpochs: number,
properties: RefereeProperties,
skip?: boolean
): ReturnType<typeof useReferral> => {
const { data, loading, error, refetch } = useRefereesQuery({
variables: {
code: referral?.data?.code as string,
aggregationEpochs,
},
skip: skip || !referral?.data?.code,
fetchPolicy: 'cache-and-network',
context: { isEnlargedTimeout: true },
});
const refetchAll = useCallback(() => {
refetch();
referral.refetch();
}, [refetch, referral]);
if (!referral.data || skip) {
return referral;
}
const referees = compact(
removePaginationWrapper(data?.referralSetReferees.edges)
);
return {
data: data && {
...referral.data,
referees: referral.data.referees.map((referee) =>
updateReferee(referee, referees, properties)
),
referee:
referral.data.referee &&
updateReferee(referral.data.referee, referees, properties),
},
loading: loading || referral.loading,
error: error || referral.error,
refetch: refetchAll,
};
};
const retrieveReferralSetData = (data: ReferralSetsQuery | undefined) =>
data?.referralSets.edges && data.referralSets.edges.length > 0
? data.referralSets.edges[0]?.node
@@ -151,6 +151,27 @@ const MOCK_REFEREES: RefereesQuery = {
},
};
const MOCK_REFEREES_30: RefereesQuery = {
referralSetReferees: {
__typename: 'ReferralSetRefereeConnection',
edges: [
{
node: {
atEpoch: 1,
joinedAt: '2023-11-21T14:17:09.257235Z',
refereeId:
'0987654321098765432109876543210987654321098765432109876543219876',
referralSetId:
'3772e570fbab89e50e563036b01dd949c554e5b5fe7908449672dfce9a8adffa',
totalRefereeGeneratedRewards: '12340',
totalRefereeNotionalTakerVolume: '56780',
__typename: 'ReferralSetReferee',
},
},
],
},
};
const programMock: MockedResponse<ReferralProgramQuery> = {
request: {
query: ReferralProgramDocument,
@@ -262,6 +283,19 @@ const refereesMock: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
},
};
const refereesMock30: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
request: {
query: RefereesDocument,
variables: {
code: MOCK_REFERRER_SET.referralSets.edges[0]?.node.id as string,
aggregationEpochs: 30,
},
},
result: {
data: MOCK_REFEREES_30,
},
};
jest.mock('@vegaprotocol/wallet', () => {
return {
...jest.requireActual('@vegaprotocol/wallet'),
@@ -297,6 +331,7 @@ describe('ReferralStatistics', () => {
noReferralSetAsRefereeMock,
stakeAvailableMock,
refereesMock,
refereesMock30,
]}
showWarnings={false}
>
@@ -313,6 +348,10 @@ describe('ReferralStatistics', () => {
expect(queryByTestId('referral-statistics')?.dataset.as).toEqual(
'referrer'
);
// gets commision from 30 epochs query
expect(queryByTestId('total-commission-value')).toHaveTextContent(
'12,340'
);
});
});
@@ -4,10 +4,15 @@ import {
VegaIcon,
VegaIconNames,
truncateMiddle,
TextChildrenTooltip as Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { DEFAULT_AGGREGATION_DAYS, useReferral } from './hooks/use-referral';
import {
DEFAULT_AGGREGATION_DAYS,
useReferral,
useUpdateReferees,
} from './hooks/use-referral';
import classNames from 'classnames';
import { Table } from './table';
import {
@@ -41,11 +46,17 @@ export const ReferralStatistics = () => {
role: 'referee',
aggregationEpochs: program.details?.windowLength,
});
const { data: referrer, refetch: referrerRefetch } = useReferral({
pubKey,
role: 'referrer',
aggregationEpochs: program.details?.windowLength,
});
const { data: referrer, refetch: referrerRefetch } = useUpdateReferees(
useReferral({
pubKey,
role: 'referrer',
aggregationEpochs: program.details?.windowLength,
}),
DEFAULT_AGGREGATION_DAYS,
['totalRefereeGeneratedRewards'],
DEFAULT_AGGREGATION_DAYS === program.details?.windowLength
);
const refetch = useCallback(() => {
refereeRefetch();
@@ -76,11 +87,9 @@ export const ReferralStatistics = () => {
export const useStats = ({
data,
program,
as,
}: {
data?: NonNullable<ReturnType<typeof useReferral>['data']>;
program: ReturnType<typeof useReferralProgram>;
as?: 'referrer' | 'referee';
}) => {
const { benefitTiers } = program;
const { data: epochData } = useCurrentEpochInfoQuery({
@@ -181,7 +190,7 @@ export const Statistics = ({
nextBenefitTierValue,
nextBenefitTierVolumeValue,
nextBenefitTierEpochsValue,
} = useStats({ data, program, as });
} = useStats({ data, program });
const isApplyCodePreview = useMemo(
() => data.referee === null,
@@ -293,11 +302,27 @@ export const Statistics = ({
.reduce((all, r) => all.plus(r), new BigNumber(0));
const totalCommissionTile = (
<StatTile
title={t('totalCommission', 'Total commission (last {{count}} epochs)', {
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
})}
description={<QUSDTooltip />}
testId="total-commission"
title={
<Trans
i18nKey="totalCommission"
defaults="Total commission (<0>last {{count}} epochs</0>)"
values={{
count: DEFAULT_AGGREGATION_DAYS,
}}
components={[
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
/>
}
description={<QUSDTooltip />}
>
{getNumberFormat(0).format(Number(totalCommissionValue))}
</StatTile>
@@ -503,12 +528,21 @@ export const RefereesTable = ({
displayName: (
<Trans
i18nKey="referralStatisticsCommission"
defaults="Commission earned in <0>qUSD</0> (last {{count}} epochs)"
defaults="Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)"
components={[
<QUSDTooltip key="0" />,
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
values={{
count:
details?.windowLength || DEFAULT_AGGREGATION_DAYS,
count: DEFAULT_AGGREGATION_DAYS,
}}
components={[<QUSDTooltip key="qusd" />]}
ns={ns}
/>
),
+2 -2
View File
@@ -31,7 +31,7 @@ export const Tile = ({
};
type StatTileProps = {
title: string;
title: ReactNode;
testId?: string;
description?: ReactNode;
children?: ReactNode;
@@ -70,7 +70,7 @@ export const StatTile = ({
export const NoProgramTile = ({ title }: Pick<StatTileProps, 'title'>) => {
const t = useT();
return (
<Tile title={title}>
<Tile>
<h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt">
{title}
</h3>
+3
View File
@@ -8,15 +8,18 @@ export const Card = ({
className,
loading = false,
highlight = false,
testId,
}: {
children: ReactNode;
title: string;
className?: string;
loading?: boolean;
highlight?: boolean;
testId?: string;
}) => {
return (
<div
data-testid={testId}
className={classNames(
'bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full p-0.5 lg:col-auto',
'rounded-lg',
@@ -84,7 +84,10 @@ export const FeesContainer = () => {
);
return (
<div className="grid auto-rows-min grid-cols-4 gap-3">
<div
className="grid auto-rows-min grid-cols-4 gap-3"
data-testid="fees-container"
>
{isConnected && (
<>
<Card
@@ -124,7 +127,10 @@ export const FeesContainer = () => {
windowLength={volumeDiscountWindowLength}
/>
) : (
<p className="text-muted pt-3 text-sm">
<p
className="text-muted pt-3 text-sm"
data-testid="no-volume-discount"
>
{t('No volume discount program active')}
</p>
)}
@@ -133,17 +139,22 @@ export const FeesContainer = () => {
title={t('Referral benefits')}
className="sm:col-span-2"
loading={loading}
data-testid="referral-benefits-card"
>
{isReferrer ? (
<ReferrerInfo code={code} />
<ReferrerInfo code={code} data-testid="referrer-info" />
) : isReferralProgramRunning ? (
<ReferralBenefits
setRunningNotionalTakerVolume={referralVolumeInWindow}
epochsInSet={epochsInSet}
epochs={referralDiscountWindowLength}
data-testid="referral-benefits"
/>
) : (
<p className="text-muted pt-3 text-sm">
<p
className="text-muted pt-3 text-sm"
data-testid="no-referral-program"
>
{t('No referral program active')}
</p>
)}
@@ -154,6 +165,7 @@ export const FeesContainer = () => {
title={t('Volume discount')}
className="lg:col-span-full xl:col-span-2"
loading={loading}
data-testid="volume-discount-card"
>
<VolumeTiers
tiers={volumeTiers}
@@ -166,6 +178,7 @@ export const FeesContainer = () => {
title={t('Referral discount')}
className="lg:col-span-full xl:col-span-2"
loading={loading}
data-testid="referral-discount-card"
>
<ReferralTiers
tiers={referralTiers}
@@ -178,6 +191,7 @@ export const FeesContainer = () => {
title={t('Fees by market')}
className="lg:col-span-full"
loading={marketsLoading}
data-testid="fees-by-market-card"
>
<MarketFees
markets={markets}
@@ -245,7 +259,7 @@ export const TradingFees = ({
}
return (
<div className="pt-4">
<div className="pt-4" data-testid="trading-fees">
<div className="leading-none">
<p className="block text-3xl leading-none" data-testid="adjusted-fees">
{minAdjustedTotal !== undefined && maxAdjustedTotal !== undefined
@@ -255,7 +269,7 @@ export const TradingFees = ({
: `${formatPercentage(adjustedTotal)}%`}
</p>
<CardTable>
<tr className="text-default">
<tr className="text-default" data-testid="total-fee-before-discount">
<CardTableTH>{t('Total fee before discount')}</CardTableTH>
<CardTableTD>
{minTotal !== undefined && maxTotal !== undefined
@@ -265,7 +279,7 @@ export const TradingFees = ({
: `${formatPercentage(total.toNumber())}%`}
</CardTableTD>
</tr>
<tr>
<tr data-testid="infrastructure-fees">
<CardTableTH>{t('Infrastructure')}</CardTableTH>
<CardTableTD>
{formatPercentage(
@@ -274,14 +288,14 @@ export const TradingFees = ({
%
</CardTableTD>
</tr>
<tr>
<tr data-testid="maker-fees">
<CardTableTH>{t('Maker')}</CardTableTH>
<CardTableTD>
{formatPercentage(Number(params.market_fee_factors_makerFee))}%
</CardTableTD>
</tr>
{minLiq && maxLiq && (
<tr>
<tr data-testid="liquidity-fees">
<CardTableTH>{t('Liquidity')}</CardTableTH>
<CardTableTD>
{formatPercentage(Number(minLiq.fees.factors.liquidityFee))}%
@@ -317,7 +331,7 @@ export const CurrentVolume = ({
const currentVolume = new BigNumber(windowLengthVolume);
return (
<div className="flex flex-col gap-3 pt-4">
<div className="flex flex-col gap-3 pt-4" data-testid="current-volume">
<CardStat
value={
currentVolume.isZero()
@@ -327,11 +341,13 @@ export const CurrentVolume = ({
text={t('pastEpochs', 'Past {{count}} epochs', {
count: windowLength,
})}
testId="past-epochs-volume"
/>
{requiredForNextTier.isGreaterThan(0) && (
<CardStat
value={formatNumber(requiredForNextTier)}
text={t('Required for next tier')}
testId="required-for-next-tier"
/>
)}
</div>
@@ -349,7 +365,7 @@ const ReferralBenefits = ({
}) => {
const t = useT();
return (
<div className="flex flex-col gap-3 pt-4">
<div className="flex flex-col gap-3 pt-4" data-testid="referral-benefits">
<CardStat
// all sets volume (not just current party)
value={formatNumber(setRunningNotionalTakerVolume)}
@@ -360,8 +376,13 @@ const ReferralBenefits = ({
count: epochs,
}
)}
testId="running-notional-taker-volume"
/>
<CardStat
value={epochsInSet}
text={t('epochs in referral set')}
testId="epochs-in-referral-set"
/>
<CardStat value={epochsInSet} text={t('epochs in referral set')} />
</div>
);
};
@@ -389,7 +410,7 @@ const TotalDiscount = ({
);
return (
<div className="pt-4">
<div className="pt-4" data-testid="total-discount-card-stats">
<CardStat
description={
<>
@@ -399,9 +420,10 @@ const TotalDiscount = ({
}
value={formatPercentage(totalDiscount) + '%'}
highlight={true}
testId="total-discount"
/>
<CardTable>
<tr>
<tr data-testid="volume-discount-row">
<CardTableTH>{t('Volume discount')}</CardTableTH>
<CardTableTD>
{formatPercentage(volumeDiscount)}%
@@ -415,7 +437,7 @@ const TotalDiscount = ({
)}
</CardTableTD>
</tr>
<tr>
<tr data-testid="referral-discount-row">
<CardTableTH>{t('Referral discount')}</CardTableTH>
<CardTableTD>
{formatPercentage(referralDiscount)}%
@@ -461,29 +483,37 @@ const VolumeTiers = ({
<div>
<Table>
<THead>
<tr>
<Th>{t('Tier')}</Th>
<Th>{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th>
<Th>
<Tr>
<Th data-testid="tier-header">{t('Tier')}</Th>
<Th data-testid="discount-header">{t('Discount')}</Th>
<Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th data-testid="my-volume-header">
{t('myVolume', 'My volume (last {{count}} epochs)', {
count: windowLength,
})}
</Th>
<Th />
</tr>
<Th data-testid="actions-header" />
</Tr>
</THead>
<tbody>
{Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i;
return (
<Tr key={i}>
<Td>{i + 1}</Td>
<Td>{formatPercentage(Number(tier.volumeDiscountFactor))}%</Td>
<Td>{formatNumber(tier.minimumRunningNotionalTakerVolume)}</Td>
<Td>{isUserTier ? formatNumber(lastEpochVolume) : ''}</Td>
<Td>{isUserTier ? <YourTier /> : null}</Td>
<Tr key={i} data-testid={`tier-row-${i}`}>
<Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td data-testid={`discount-value-${i}`}>
{formatPercentage(Number(tier.volumeDiscountFactor))}%
</Td>
<Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`my-volume-value-${i}`}>
{isUserTier ? formatNumber(lastEpochVolume) : ''}
</Td>
<Td data-testid={`your-tier-${i}`}>
{isUserTier ? <YourTier /> : null}
</Td>
</Tr>
);
})}
@@ -520,39 +550,53 @@ const ReferralTiers = ({
<div>
<Table>
<THead>
<tr>
<Th>{t('Tier')}</Th>
<Th>{t('Discount')}</Th>
<Th>{t('Min. trading volume')}</Th>
<Th>{t('Required epochs')}</Th>
<Th />
</tr>
<Tr>
<Th data-testid="tier-header">{t('Tier')}</Th>
<Th data-testid="discount-header">{t('Discount')}</Th>
<Th data-testid="min-volume-header">{t('Min. trading volume')}</Th>
<Th data-testid="required-epochs-header">{t('Required epochs')}</Th>
<Th data-testid="extra-header" />
</Tr>
</THead>
<tbody>
{Array.from(tiers).map((t, i) => {
{Array.from(tiers).map((tier, i) => {
const isUserTier = tierIndex === i;
const requiredVolume = Number(t.minimumRunningNotionalTakerVolume);
const requiredVolume = Number(
tier.minimumRunningNotionalTakerVolume
);
let unlocksIn = null;
if (
referralVolumeInWindow >= requiredVolume &&
epochsInSet < t.minimumEpochs
epochsInSet < tier.minimumEpochs
) {
unlocksIn = (
<span className="text-muted">
Unlocks in {t.minimumEpochs - epochsInSet} epochs
Unlocks in {tier.minimumEpochs - epochsInSet} epochs
</span>
);
}
return (
<Tr key={i}>
<Td>{i + 1}</Td>
<Td>{formatPercentage(Number(t.referralDiscountFactor))}%</Td>
<Td>{formatNumber(t.minimumRunningNotionalTakerVolume)}</Td>
<Td>{t.minimumEpochs}</Td>
<Td>{isUserTier ? <YourTier /> : unlocksIn}</Td>
<Tr key={i} data-testid={`tier-row-${i}`}>
<Td data-testid={`tier-value-${i}`}>{i + 1}</Td>
<Td data-testid={`discount-value-${i}`}>
{formatPercentage(Number(tier.referralDiscountFactor))}%
</Td>
<Td data-testid={`min-volume-value-${i}`}>
{formatNumber(tier.minimumRunningNotionalTakerVolume)}
</Td>
<Td data-testid={`required-epochs-value-${i}`}>
{tier.minimumEpochs}
</Td>
<Td data-testid={`user-tier-or-unlocks-${i}`}>
{isUserTier ? (
<YourTier testId={`your-tier-${i}`} />
) : (
unlocksIn
)}
</Td>
</Tr>
);
})}
@@ -562,11 +606,18 @@ const ReferralTiers = ({
);
};
const YourTier = () => {
interface YourTierProps {
testId?: string;
}
const YourTier = ({ testId }: YourTierProps) => {
const t = useT();
return (
<span className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white">
<span
className="bg-rainbow whitespace-nowrap rounded-xl px-4 py-1.5 text-white"
data-testid={testId}
>
{t('Your tier')}
</span>
);
@@ -3,21 +3,31 @@ import type { ReactNode } from 'react';
const cellClass = 'px-4 py-2 text-xs font-normal text-left last:text-right';
export const Th = ({ children }: { children?: ReactNode }) => {
export const Th = ({ children, ...props }: { children?: ReactNode }) => {
return (
<th className={classNames(cellClass, 'text-secondary leading-none py-3')}>
<th
className={classNames(cellClass, 'text-secondary leading-none py-3')}
{...props}
>
{children}
</th>
);
};
export const Td = ({ children }: { children?: ReactNode }) => {
return <th className={cellClass}>{children}</th>;
export const Td = ({ children, ...props }: { children?: ReactNode }) => {
return (
<th className={cellClass} {...props}>
{children}
</th>
);
};
export const Tr = ({ children }: { children?: ReactNode }) => {
export const Tr = ({ children, ...props }: { children?: ReactNode }) => {
return (
<tr className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700">
<tr
className="hover:bg-vega-clight-600 dark:hover:bg-vega-cdark-700"
{...props}
>
{children}
</tr>
);
@@ -24,7 +24,13 @@ import classNames from 'classnames';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t';
export const VegaWalletConnectButton = () => {
export const VegaWalletConnectButton = ({
intent = Intent.None,
onClick,
}: {
intent?: Intent;
onClick?: () => void;
}) => {
const t = useT();
const [dropdownOpen, setDropdownOpen] = useState(false);
const openVegaWalletDialog = useVegaWalletDialogStore(
@@ -117,9 +123,12 @@ export const VegaWalletConnectButton = () => {
return (
<Button
data-testid="connect-vega-wallet"
onClick={openVegaWalletDialog}
onClick={() => {
onClick?.();
openVegaWalletDialog();
}}
size="small"
intent={Intent.None}
intent={intent}
icon={<VegaIcon name={VegaIconNames.ARROW_RIGHT} size={14} />}
>
<span className="whitespace-nowrap uppercase">
+6
View File
@@ -24,6 +24,12 @@ poetry shell
5. **Install python dependencies**
To make sure you are on the latest version of our market-sim branch.
```bash
poetry update vega-sim
```
```bash
poetry install
```
+3 -2
View File
@@ -55,14 +55,14 @@ def change_keys(page: Page, vega: VegaServiceNull, key_name):
page.reload()
def forward_time(vega: VegaServiceNull, forward_epoch: bool = False):
def forward_time(vega:VegaServiceNull, forward_epoch: bool = False):
vega.wait_fn(1)
vega.wait_for_total_catchup()
if forward_epoch:
next_epoch(vega)
# This is for when the element will initially load but contain an outdated value. It will wait for the element to contain the expected text, returning False after a timeout or exception
def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
try:
@@ -71,3 +71,4 @@ def selector_contains_text(page: Page, selector, expected_text, timeout=5000):
return True
except:
return False
+8
View File
@@ -245,3 +245,11 @@ def setup_perps_market(
vega.wait_for_total_catchup()
return market_id
def market_exists(vega: VegaService, market_id: str):
if market_id is None:
return False
all_markets = vega.all_markets()
market_ids = [market.id for market in all_markets]
return market_id in market_ids
+14 -8
View File
@@ -56,11 +56,12 @@ label_value_tooltip_pairs = [
def tooltip(page: Page, index: int, test_id: str, tooltip: str):
page.locator(f"data-testid={index}_{test_id}").hover()
expect(page.locator('[role="tooltip"]').locator("div")).to_have_text(tooltip)
expect(page.locator('[role="tooltip"]').locator(
"div")).to_have_text(tooltip)
page.get_by_test_id("dialog-title").click()
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
def test_asset_details(page: Page):
page.goto("/#/portfolio")
page.locator('[data-testid="tab-collateral"] >> text=tDAI').click()
@@ -73,17 +74,22 @@ def test_asset_details(page: Page):
value = pair.get("value", "")
label_tooltip = pair.get("labelTooltip", "")
value_tooltip = pair.get("valueToolTip", "")
if label == "ID":
expect(page.get_by_role("button", name="Copy id to clipboard")).to_be_visible()
asset_id_text = page.locator(f"[data-testid='{index}_value']").inner_text()
expect(page.get_by_role(
"button", name="Copy id to clipboard")).to_be_visible()
asset_id_text = page.locator(
f"[data-testid='{index}_value']").inner_text()
pattern = r"^[0-9a-f]{6}\u2026[0-9a-f]{4}"
assert re.match(pattern, asset_id_text), f"Expected ID to match pattern but got {asset_id_text}"
assert re.match(
pattern, asset_id_text), f"Expected ID to match pattern but got {asset_id_text}"
else:
expect(page.locator(f"[data-testid='{index}_label']")).to_have_text(label)
expect(page.locator(f"[data-testid='{index}_value']")).to_have_text(value)
expect(page.locator(
f"[data-testid='{index}_label']")).to_have_text(label)
expect(page.locator(
f"[data-testid='{index}_value']")).to_have_text(value)
if label_tooltip:
tooltip(page, index, "label", label_tooltip)
@@ -14,19 +14,16 @@ market_order = "order-type-Market"
tif = "order-tif"
expire = "expire"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
def continuous_market(vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("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)")
@@ -54,8 +51,7 @@ def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10+10LimitFilled120.00GTT:"
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_buy_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
@@ -72,8 +68,7 @@ def test_limit_buy_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10+10LimitFilled120.00GTC"
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_sell_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("10")
@@ -97,8 +92,7 @@ def test_limit_sell_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10-10LimitFilled100.00GFN"
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_market_sell_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(market_order).click()
@@ -122,8 +116,7 @@ def test_market_sell_order(continuous_market, vega: VegaService, page: Page):
"BTC:DAI_2023Futr10-10MarketFilled-IOC"
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_market_buy_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(market_order).click()
@@ -13,7 +13,7 @@ def continuous_market(vega):
return setup_continuous_market(vega)
@pytest.mark.skip("We currently can't approve wallet connection through Sim")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_connect_vega_wallet(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("order-price").fill("101")
@@ -25,7 +25,7 @@ def test_connect_vega_wallet(continuous_market, page: Page):
expect(page.get_by_test_id("order-type-Limit")).to_be_checked()
expect(page.get_by_test_id("order-price")).to_have_value("101")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_sidebar_should_be_open_after_reload(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()
@@ -12,7 +12,7 @@ market_trading_mode = "market-trading-mode"
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_margin_and_fees_estimations(continuous_market, vega: VegaService, page: Page):
# setup continuous trading market with one user buy trade
market_id = continuous_market
@@ -38,7 +38,6 @@ timeInForce_col = '[col-id="submission.timeInForce"]'
updatedAt_col = '[col-id="updatedAt"]'
close_toast = "toast-close"
def create_position(vega: VegaService, market_id):
submit_order(vega, "Key 1", market_id, "SIDE_SELL", 100, 110)
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 100, 110)
@@ -46,7 +45,7 @@ def create_position(vega: VegaService, market_id):
vega.wait_fn(1)
vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_order_form_error_validation(continuous_market, page: Page):
# 7002-SORD-032
page.goto(f"/#/markets/{continuous_market}")
@@ -69,7 +68,7 @@ def test_stop_order_form_error_validation(continuous_market, page: Page):
)
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_order_rejected(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click()
@@ -107,7 +106,7 @@ def test_submit_stop_order_rejected(continuous_market, vega: VegaService, page:
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_market_order_triggered(
continuous_market, vega: VegaService, page: Page
):
@@ -165,7 +164,7 @@ def test_submit_stop_market_order_triggered(
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_limit_order_pending(
continuous_market, vega: VegaService, page: Page
):
@@ -226,7 +225,7 @@ def test_submit_stop_limit_order_pending(
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_limit_order_cancel(
continuous_market, vega: VegaService, page: Page
):
@@ -270,7 +269,7 @@ class TestStopOcoValidation:
def continuous_market(self, vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_market_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-052
# 7002-SORD-055
@@ -303,7 +302,7 @@ class TestStopOcoValidation:
expect(page.get_by_test_id(order_size)).to_be_empty
expect(page.get_by_test_id(order_price)).not_to_be_visible()
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_stop_limit_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-020
# 7002-SORD-021
@@ -347,7 +346,7 @@ class TestStopOcoValidation:
expect(page.get_by_test_id(order_price)).to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_maximum_number_of_active_stop_orders(
self, continuous_market, vega: VegaService, page: Page
):
@@ -4,7 +4,6 @@ from vega_sim.service import VegaService
from actions.vega import submit_order
from actions.utils import wait_for_toast_confirmation
stop_order_btn = "order-type-Stop"
stop_limit_order_btn = "order-type-StopLimit"
stop_market_order_btn = "order-type-StopMarket"
@@ -50,7 +49,7 @@ def create_position(vega: VegaService, market_id):
vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_order_market_oco_rejected(
continuous_market, vega: VegaService, page: Page
):
@@ -127,7 +126,7 @@ def test_submit_stop_order_market_oco_rejected(
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_market_order_triggered(
continuous_market, vega: VegaService, page: Page
):
@@ -204,7 +203,7 @@ def test_submit_stop_oco_market_order_triggered(
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_market_order_pending(
continuous_market, vega: VegaService, page: Page
):
@@ -236,7 +235,7 @@ def test_submit_stop_oco_market_order_pending(
"PendingOCO"
)
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_limit_order_pending(
continuous_market, vega: VegaService, page: Page
):
@@ -287,7 +286,7 @@ def test_submit_stop_oco_limit_order_pending(
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_submit_stop_oco_limit_order_cancel(
continuous_market, vega: VegaService, page: Page
):
@@ -325,5 +324,3 @@ def test_submit_stop_oco_limit_order_cancel(
expect(
page.locator(".ag-center-cols-container").locator('[col-id="status"]').last
).to_have_text("CancelledOCO")
@@ -5,8 +5,6 @@ from actions.utils import change_keys
from conftest import init_vega
from fixtures.market import setup_continuous_market
order_size = "order-size"
order_price = "order-price"
place_order = "place-order"
@@ -18,13 +16,12 @@ def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
def continuous_market(vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_should_display_info_and_button_for_deposit(continuous_market, vega: VegaService, page: Page):
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_should_display_info_and_button_for_deposit(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("200000")
page.get_by_test_id(order_price).fill("20")
@@ -35,7 +32,7 @@ def test_should_display_info_and_button_for_deposit(continuous_market, vega: Veg
page.get_by_test_id(deal_ticket_deposit_dialog_button).nth(0).click()
expect(page.get_by_test_id("sidebar-content")).to_contain_text("DepositFrom")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_should_show_an_error_if_your_balance_is_zero(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
vega.create_key("key_empty")
+682
View File
@@ -0,0 +1,682 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from wallet_config import MM_WALLET
from conftest import init_vega, init_page, auth_setup
from actions.utils import next_epoch, change_keys, forward_time
from fixtures.market import market_exists, setup_continuous_market
# region Constants for test IDs
ADJUSTED_FEES = "adjusted-fees"
TOTAL_FEE_BEFORE_DISCOUNT = "total-fee-before-discount"
INFRASTRUCTURE_FEES = "infrastructure-fees"
MAKER_FEES = "maker-fees"
LIQUIDITY_FEES = "liquidity-fees"
TOTAL_DISCOUNT = "total-discount"
VOLUME_DISCOUNT_ROW = "volume-discount-row"
REFERRAL_DISCOUNT_ROW = "referral-discount-row"
PAST_EPOCHS_VOLUME = "past-epochs-volume"
REQUIRED_FOR_NEXT_TIER = "required-for-next-tier"
TIER_VALUE_0 = "tier-value-0"
TIER_VALUE_1 = "tier-value-1"
DISCOUNT_VALUE_0 = "discount-value-0"
DISCOUNT_VALUE_1 = "discount-value-1"
MIN_VOLUME_VALUE_0 = "min-volume-value-0"
MIN_VOLUME_VALUE_1 = "min-volume-value-1"
MY_VOLUME_VALUE_0 = "my-volume-value-0"
MY_VOLUME_VALUE_1 = "my-volume-value-1"
YOUR_TIER_0 = "your-tier-0"
YOUR_TIER_1 = "your-tier-1"
ORDER_SIZE = "order-size"
ORDER_PRICE = "order-price"
DISCOUNT_PILL = "discount-pill"
FEES_TEXT = "fees-text"
TOOLTIP_CONTENT = "tooltip-content"
INFRASTRUCTURE_FEE_FACTOR = "infrastructure-fee-factor"
INFRASTRUCTURE_FEE_VALUE = "infrastructure-fee-value"
LIQUIDITY_FEE_FACTOR = "liquidity-fee-factor"
LIQUIDITY_FEE_VALUE = "liquidity-fee-value"
MAKER_FEE_FACTOR = "maker-fee-factor"
MAKER_FEE_VALUE = "maker-fee-value"
SUBTOTAL_FEE_FACTOR = "subtotal-fee-factor"
SUBTOTAL_FEE_VALUE = "subtotal-fee-value"
DISCOUNT_FEE_FACTOR = "discount-fee-factor"
DISCOUNT_FEE_VALUE = "discount-fee-value"
TOTAL_FEE_VALUE = "total-fee-value"
RUNNING_NOTIONAL_TAKER_VOLUME = "running-notional-taker-volume"
EPOCHS_IN_REFERRAL_SET = "epochs-in-referral-set"
REQUIRED_EPOCHS_VALUE_0 = "required-epochs-value-0"
REQUIRED_EPOCHS_VALUE_1 = "required-epochs-value-1"
FILLS = "Fills"
TAB_FILLS = "tab-fills"
FEE_BREAKDOWN_TOOLTIP = "fee-breakdown-tooltip"
ROW_LOCATOR = ".ag-center-cols-container .ag-row"
# Col-Ids:
COL_INSTRUMENT_CODE = '[col-id="market.tradableInstrument.instrument.code"]'
COL_CODE = '[col-id="code"]'
COL_SIZE = '[col-id="size"]'
COL_PRICE = '[col-id="price"]'
COL_PRICE_1 = '[col-id="price_1"]'
COL_AGGRESSOR = '[col-id="aggressor"]'
COL_FEE = '[col-id="fee"]'
COL_FEE_DISCOUNT = '[col-id="fee-discount"]'
COL_FEE_AFTER_DISCOUNT = '[col-id="feeAfterDiscount"]'
COL_INFRA_FEE = '[col-id="infraFee"]'
COL_MAKER_FEE = '[col-id="makerFee"]'
COL_LIQUIDITY_FEE = '[col-id="liquidityFee"]'
COL_TOTAL_FEE = '[col-id="totalFee"]'
# endregion
@pytest.fixture(scope="module")
def market_ids():
return {
"tier_1_volume": "default_id",
"tier_2_volume": "default_id",
"tier_1_referral": "default_id",
"tier_2_referral": "default_id",
"combo": "default_id",
}
@pytest.fixture(scope="module")
def vega_volume_discount_tier_1(request):
with init_vega(request) as vega_volume_discount_tier_1:
yield vega_volume_discount_tier_1
@pytest.fixture(scope="module")
def vega_volume_discount_tier_2(request):
with init_vega(request) as vega_volume_discount_tier_2:
yield vega_volume_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_discount_tier_1(request):
with init_vega(request) as vega_referral_discount_tier_1:
yield vega_referral_discount_tier_1
@pytest.fixture(scope="module")
def vega_referral_discount_tier_2(request):
with init_vega(request) as vega_referral_discount_tier_2:
yield vega_referral_discount_tier_2
@pytest.fixture(scope="module")
def vega_referral_and_volume_discount(request):
with init_vega(request) as vega_referral_and_volume_discount:
yield vega_referral_and_volume_discount
@pytest.fixture
def page(vega_instance, browser, request):
with init_page(vega_instance, browser, request) as page_instance:
yield page_instance
@pytest.fixture
def vega_instance(
tier,
discount_program,
vega_volume_discount_tier_1,
vega_volume_discount_tier_2,
vega_referral_discount_tier_1,
vega_referral_discount_tier_2,
vega_referral_and_volume_discount,
):
if discount_program == "volume":
return vega_volume_discount_tier_1 if tier == 1 else vega_volume_discount_tier_2
elif discount_program == "referral":
return (
vega_referral_discount_tier_1
if tier == 1
else vega_referral_discount_tier_2
)
elif discount_program == "combo":
return vega_referral_and_volume_discount
@pytest.fixture
def auth(vega_instance, page):
return auth_setup(vega_instance, page)
def setup_market_with_volume_discount_program(vega: VegaService, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
order_count = 2 if tier == 1 else 3
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", 1, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_market_with_referral_discount_program(vega: VegaService, tier: int):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 1 if tier == 1 else 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def setup_combined_market(vega: VegaService):
market = setup_continuous_market(vega, custom_quantum=100000)
vega.update_volume_discount_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"volume_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"volume_discount_factor": 0.2,
},
],
window_length=7,
)
next_epoch(vega=vega)
vega.update_referral_program(
proposal_key=MM_WALLET.name,
benefit_tiers=[
{
"minimum_running_notional_taker_volume": 100,
"minimum_epochs": 1,
"referral_reward_factor": 0.1,
"referral_discount_factor": 0.1,
},
{
"minimum_running_notional_taker_volume": 200,
"minimum_epochs": 2,
"referral_reward_factor": 0.2,
"referral_discount_factor": 0.2,
},
],
staking_tiers=[
{"minimum_staked_tokens": 100, "referral_reward_multiplier": 1.1},
{"minimum_staked_tokens": 200, "referral_reward_multiplier": 1.2},
],
window_length=1,
)
vega.create_referral_set(key_name=MM_WALLET.name)
next_epoch(vega=vega)
referral_set_id = list(vega.list_referral_sets().keys())[0]
vega.apply_referral_code(key_name="Key 1", id=referral_set_id)
next_epoch(vega=vega)
order_count = 2
order_size = 2
for _ in range(order_count):
submit_order(vega, "Key 1", market, "SIDE_BUY", order_size, 110)
forward_time(vega, True if _ < order_count - 1 else False)
return market
def set_market_volume_discount(vega, tier, discount_program, market_ids):
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key, "default_id")
print(f"Checking if market exists: {market_id}")
if not market_exists(vega, market_id):
print(
f"Market doesn't exist for {discount_program} tier {tier}. Setting up new market."
)
if discount_program == "volume":
market_id = setup_market_with_volume_discount_program(vega, tier)
elif discount_program == "referral":
market_id = setup_market_with_referral_discount_program(vega, tier)
elif discount_program == "combo":
market_id = setup_combined_market(vega)
market_ids[market_id_key] = market_id
print(f"Using market ID: {market_id}")
return market_ids
@pytest.mark.parametrize(
"tier, discount_program, expected_text",
[
(1, "volume", "9.045%-9.045%"),
(2, "volume", "8.04%-8.04%"),
(1, "referral", "9.045%-9.045%"),
(2, "referral", "8.04%-8.04%"),
(2, "combo", "6.432%-6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_my_trading_fees(
tier, expected_text, discount_program, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(ADJUSTED_FEES)).to_have_text(expected_text)
expect(page.get_by_test_id(TOTAL_FEE_BEFORE_DISCOUNT)).to_have_text(
"Total fee before discount10.05%-10.05%"
)
expect(page.get_by_test_id(INFRASTRUCTURE_FEES)).to_have_text("Infrastructure0.05%")
expect(page.get_by_test_id(MAKER_FEES)).to_have_text("Maker10%")
expect(page.get_by_test_id(LIQUIDITY_FEES)).to_have_text("Liquidity0%-0%")
@pytest.mark.parametrize(
"tier, discount_program, volume_discount, total_discount, referral_discount",
[
(1, "volume", "Volume discount10%", "10%", "Referral discount0%"),
(2, "volume", "Volume discount20%", "20%", "Referral discount0%"),
(1, "referral", "Volume discount0%", "10%", "Referral discount10%"),
(2, "referral", "Volume discount0%", "20%", "Referral discount20%"),
(2, "combo", "Volume discount20%", "36%", "Referral discount20%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_total_discount(
tier,
discount_program,
volume_discount,
referral_discount,
total_discount,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TOTAL_DISCOUNT)).to_have_text(total_discount)
expect(page.get_by_test_id(VOLUME_DISCOUNT_ROW)).to_have_text(volume_discount)
expect(page.get_by_test_id(REFERRAL_DISCOUNT_ROW)).to_have_text(referral_discount)
page.get_by_test_id(TOTAL_DISCOUNT).hover()
expect(page.get_by_test_id(TOOLTIP_CONTENT).nth(0)).to_have_text(
"The total discount is calculated according to the following formula: 1 - (1 - dvolume) ⋇ (1 - dreferral)"
)
@pytest.mark.parametrize(
"tier, discount_program, past_epochs_volume, required_for_next_tier",
[(1, "volume", "103", "97"), (2, "volume", "206", "")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_volume_discount_program_my_current_volume(
tier,
discount_program,
past_epochs_volume,
required_for_next_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(PAST_EPOCHS_VOLUME)).to_have_text(past_epochs_volume)
if tier == 1:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).to_have_text(
required_for_next_tier
)
else:
expect(page.get_by_test_id(REQUIRED_FOR_NEXT_TIER)).not_to_be_visible()
@pytest.mark.parametrize(
"tier, discount_program, notional_taker_volume, epochs_in_set",
[(1, "referral", "103", "1"), (2, "referral", "207", "1")],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_referral_discount_program_referral_benefits(
tier,
vega_instance,
discount_program,
notional_taker_volume,
epochs_in_set,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(RUNNING_NOTIONAL_TAKER_VOLUME)).to_have_text(
notional_taker_volume
)
expect(page.get_by_test_id(EPOCHS_IN_REFERRAL_SET)).to_have_text(epochs_in_set)
@pytest.mark.parametrize(
"tier, discount_program, my_volume_test_id, my_volume_value, your_tier",
[
(1, "volume", "my-volume-value-0", "103", "your-tier-0"),
(2, "volume", "my-volume-value-1", "206", "your-tier-1"),
(1, "referral", "my-volume-value-0", "103", "your-tier-0"),
(2, "referral", "my-volume-value-1", "206", "your-tier-1"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_discount(
tier,
discount_program,
my_volume_test_id,
my_volume_value,
your_tier,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
expect(page.get_by_test_id(TIER_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(TIER_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(DISCOUNT_VALUE_0)).to_have_text("10%")
expect(page.get_by_test_id(DISCOUNT_VALUE_1)).to_have_text("20%")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_0)).to_have_text("100")
expect(page.get_by_test_id(MIN_VOLUME_VALUE_1)).to_have_text("200")
if discount_program == "volume":
expect(page.get_by_test_id(my_volume_test_id)).to_have_text(my_volume_value)
else:
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_0)).to_have_text("1")
expect(page.get_by_test_id(REQUIRED_EPOCHS_VALUE_1)).to_have_text("2")
expect(page.get_by_test_id(your_tier)).to_be_visible()
expect(page.get_by_test_id(your_tier)).to_have_text("Your tier")
@pytest.mark.parametrize(
"tier, discount_program, fees_after_discount",
[
(1, "volume", "9.045%"),
(2, "volume", "8.04%"),
(1, "referral", "9.045%"),
(2, "referral", "8.04%"),
(2, "combo", "6.432%"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fees_page_discount_program_fees_by_market(
tier, discount_program, fees_after_discount, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
page.goto("/#/fees")
row = page.locator(ROW_LOCATOR)
expect(row.locator(COL_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_FEE_AFTER_DISCOUNT)).to_have_text(fees_after_discount)
expect(row.locator(COL_INFRA_FEE)).to_have_text("0.05%")
expect(row.locator(COL_MAKER_FEE)).to_have_text("10%")
expect(row.locator(COL_LIQUIDITY_FEE)).to_have_text("0%")
expect(row.locator(COL_TOTAL_FEE)).to_have_text("10.05%")
@pytest.mark.parametrize(
"tier, discount_program, discount, discount_value, total_fee",
[
(1, "volume", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "volume", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(1, "referral", "-10%", "-0.01005 tDAI", "0.09045 tDAI"),
(2, "referral", "-20%", "-0.0201 tDAI", "0.0804 tDAI"),
(2, "combo", "-36%", "-0.03618 tDAI", "0.06432 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_deal_ticket_discount_program(
tier,
discount_program,
discount,
discount_value,
total_fee,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(ORDER_SIZE).fill("1")
page.get_by_test_id(ORDER_PRICE).fill("1")
expect(page.get_by_test_id(DISCOUNT_PILL)).to_have_text(discount)
page.get_by_test_id(FEES_TEXT).hover()
tooltip = page.get_by_test_id(TOOLTIP_CONTENT).first
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_FACTOR)).to_have_text("0.05%")
expect(tooltip.get_by_test_id(INFRASTRUCTURE_FEE_VALUE)).to_have_text("0.0005 tDAI")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_FACTOR)).to_have_text("0%")
expect(tooltip.get_by_test_id(LIQUIDITY_FEE_VALUE)).to_have_text("0.00 tDAI")
expect(tooltip.get_by_test_id(MAKER_FEE_FACTOR)).to_have_text("10%")
expect(tooltip.get_by_test_id(MAKER_FEE_VALUE)).to_have_text("0.10 tDAI")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_FACTOR)).to_have_text("10.05%")
expect(tooltip.get_by_test_id(SUBTOTAL_FEE_VALUE)).to_have_text("0.1005 tDAI")
expect(tooltip.get_by_test_id(DISCOUNT_FEE_FACTOR)).to_have_text(discount)
expect(tooltip.get_by_test_id(DISCOUNT_FEE_VALUE)).to_have_text(discount_value)
expect(tooltip.get_by_test_id(TOTAL_FEE_VALUE)).to_have_text(total_fee)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, price_1, size",
[
(1, "volume", "9.36158 tDAI", "1.04017 tDAI", "103.50 tDAI", "+1"),
(2, "volume", "8.3214 tDAI", "2.08035 tDAI", "103.50 tDAI", "+1"),
(
1,
"referral",
"8.42543 tDAI ",
"1.04017 tDAI",
"103.50 tDAI",
"+1",
),
(
2,
"referral",
"13.31424 tDAI",
"4.1607 tDAI",
"207.00 tDAI",
"+2",
),
(2, "combo", "10.6514 tDAI ", "7.48926 tDAI", "207.00 tDAI", "+2"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_discount_program(
tier,
discount_program,
fee,
fee_discount,
price_1,
size,
vega_instance,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Taker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee, fee_discount, size, price_1",
[
(1, "volume", "-9.315 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "volume", "-8.28 tDAI", "2.07 tDAI", "-1", "103.50 tDAI"),
(1, "referral", "-8.3835 tDAI", "1.035 tDAI", "-1", "103.50 tDAI"),
(2, "referral", "-13.248 tDAI", "4.14 tDAI", "-2", "207.00 tDAI"),
(2, "combo", "-10.5984 tDAI ", "7.452 tDAI", "-2", "207.00 tDAI"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_discount_program(
tier,
discount_program,
vega_instance,
fee,
fee_discount,
size,
price_1,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
change_keys(page, vega_instance, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
expect(row.locator(COL_INSTRUMENT_CODE)).to_have_text("BTC:DAI_2023Futr")
expect(row.locator(COL_SIZE)).to_have_text(size)
expect(row.locator(COL_PRICE)).to_have_text("103.50 tDAI")
expect(row.locator(COL_PRICE_1)).to_have_text(price_1)
expect(row.locator(COL_AGGRESSOR)).to_have_text("Maker")
expect(row.locator(COL_FEE)).to_have_text(fee)
expect(row.locator(COL_FEE_DISCOUNT)).to_have_text(fee_discount)
@pytest.mark.parametrize(
"tier, discount_program, fee",
[
(1, "volume", "9.315"),
(2, "volume", "8.28"),
(1, "referral", "8.3835"),
(2, "referral", "13.248"),
(2, "combo", "10.5984"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_maker_fee_tooltip_discount_program(
tier, discount_program, fee, vega_instance, page: Page, market_ids
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
change_keys(page, vega_instance, MM_WALLET.name)
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeThe maker will receive the maker fee.If the market is active the maker will pay zero infrastructure and liquidity fees.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee-{fee} tDAITotal fees-{fee} tDAI"
)
@pytest.mark.parametrize(
"tier, discount_program, maker_fee, total_fee, infra_fee",
[
(1, "volume", "9.315", "9.36158", "0.04658"),
(2, "volume", "8.28", "8.3214", "0.0414"),
(1, "referral", "8.3835", "8.42543", "0.04193"),
(2, "referral", "13.248", "13.31424", "0.06624"),
(2, "combo", "10.5984", "10.6514", "0.053"),
],
)
@pytest.mark.usefixtures("risk_accepted", "auth", "market_ids")
def test_fills_taker_fee_tooltip_discount_program(
tier,
discount_program,
vega_instance,
maker_fee,
total_fee,
infra_fee,
page: Page,
market_ids,
):
market_ids = set_market_volume_discount(
vega_instance, tier, discount_program, market_ids
)
market_id_key = f"tier_{tier}_{discount_program}"
if discount_program == "combo":
market_id_key = "combo"
market_id = market_ids.get(market_id_key)
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(FILLS).click()
row = page.get_by_test_id(TAB_FILLS).locator(ROW_LOCATOR).first
row.locator(COL_FEE).hover()
expect(page.get_by_test_id(FEE_BREAKDOWN_TOOLTIP)).to_have_text(
f"If the market was activeFees to be paid by the taker.Infrastructure fee{infra_fee} tDAILiquidity fee0.00 tDAIMaker fee{maker_fee} tDAITotal fees{total_fee} tDAI"
)
@@ -10,20 +10,16 @@ import logging
logger = logging.getLogger()
@pytest.fixture(scope="class")
def vega():
with init_vega() as vega:
yield vega
# we can reuse vega market-sim service and market in almost all tests
@pytest.fixture(scope="class")
def simple_market(vega: VegaService):
return setup_simple_market(vega)
class TestGetStarted:
@pytest.mark.usefixtures("page")
def test_get_started_interactive(self, vega: VegaService, page: Page):
page.goto("/")
# 0007-FUGS-001
@@ -134,8 +130,7 @@ class TestGetStarted:
# Assert dialog isn't visible
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_get_started_seen_already(self, simple_market, page: Page):
page.goto(f"/#/markets/{simple_market}")
get_started_locator = page.get_by_test_id("connect-vega-wallet")
@@ -148,8 +143,6 @@ class TestGetStarted:
# 0007-FUGS-007
expect(page.get_by_test_id("dialog-content").nth(1)).to_be_visible()
@pytest.mark.usefixtures("page")
def test_browser_wallet_installed(self, simple_market, page: Page):
page.add_init_script("window.vega = {}")
page.goto(f"/#/markets/{simple_market}")
@@ -159,14 +152,13 @@ class TestGetStarted:
expect(locator).to_be_visible
expect(locator).to_have_text("Connect")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_get_started_deal_ticket(self,simple_market, page: Page):
page.goto(f"/#/markets/{simple_market}")
expect(page.get_by_test_id("order-connect-wallet")).to_have_text("Connect wallet")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_browser_wallet_installed_deal_ticket(simple_market, page: Page):
page.add_init_script("window.vega = {}")
page.goto(f"/#/markets/{simple_market}")
@@ -174,7 +166,6 @@ class TestGetStarted:
page.wait_for_selector('[data-testid="sidebar-content"]', state="visible")
expect(page.get_by_test_id("get-started-banner")).not_to_be_visible()
@pytest.mark.usefixtures("page")
def test_redirect_default_market(self, continuous_market, vega: VegaService, page: Page):
page.goto("/")
# 0007-FUGS-012
@@ -186,7 +177,6 @@ class TestGetStarted:
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
class TestBrowseAll:
@pytest.mark.usefixtures("page")
def test_get_started_browse_all(self, simple_market, vega: VegaService, page: Page):
page.goto("/")
print(simple_market)
@@ -11,7 +11,6 @@ def hover_and_assert_tooltip(page: Page, element_text):
element.hover()
expect(page.get_by_role("tooltip")).to_be_visible()
class TestIcebergOrdersValidations:
@pytest.fixture(scope="class")
def vega(self, request):
@@ -22,7 +21,7 @@ class TestIcebergOrdersValidations:
def continuous_market(self, vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_iceberg_submit(self, continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("iceberg").click()
@@ -47,7 +46,7 @@ class TestIcebergOrdersValidations:
(page.get_by_role("row").locator('[col-id="type"]')).nth(1)
).to_have_text("Limit (Iceberg)")
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
@@ -17,27 +17,34 @@ def continuous_market(vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_liquidity_provision_amendment(continuous_market, vega: VegaService, page: Page):
# TODO Refactor asserting the grid
page.goto(f"/#/liquidity/{continuous_market}")
change_keys(page, vega, "market_maker")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Active"
)
# 5002-LIQP-006
expect(page.get_by_test_id("target-stake")).to_have_text("Target stake5.82757 tDAI")
expect(page.get_by_test_id("target-stake")
).to_have_text("Target stake5.82757 tDAI")
# 5002-LIQP-007
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake10,000.00 tDAI")
expect(page.get_by_test_id("supplied-stake")
).to_have_text("Supplied stake10,000.00 tDAI")
# 5002-LIQP-008
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 171,598.11%")
expect(page.get_by_test_id("liquidity-supplied")
).to_have_text("Liquidity supplied 171,598.11%")
expect(page.get_by_test_id("fees-paid")).to_have_text("Fees paid-")
# 5002-LIQP-009
expect(page.get_by_test_id("liquidity-market-id")).to_have_text("Market ID" + truncate_middle(continuous_market))
expect(page.get_by_test_id("liquidity-learn-more")).to_have_text("Learn moreProviding liquidity")
expect(page.get_by_test_id("liquidity-market-id")
).to_have_text("Market ID" + truncate_middle(continuous_market))
expect(page.get_by_test_id("liquidity-learn-more")
).to_have_text("Learn moreProviding liquidity")
# 002-LIQP-010
expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision")
expect(page.get_by_test_id("liquidity-learn-more").get_by_test_id("external-link")
).to_have_attribute("href", "https://docs.vega.xyz/testnet/concepts/liquidity/provision")
vega.submit_simple_liquidity(
key_name="market_maker",
@@ -50,26 +57,32 @@ def test_liquidity_provision_amendment(continuous_market, vega: VegaService, pag
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.reload()
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Updating next epoch"
)
next_epoch(vega=vega)
page.reload()
expect(page.get_by_test_id("supplied-stake")).to_have_text("Supplied stake1.00001 tDAI")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 17.16%")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(page.get_by_test_id("supplied-stake")
).to_have_text("Supplied stake1.00001 tDAI")
expect(page.get_by_test_id("liquidity-supplied")
).to_have_text("Liquidity supplied 17.16%")
row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Active"
)
@pytest.mark.skip("Waiting for the ability to cancel LP")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page: Page):
# TODO Refactor asserting the grid
page.goto(f"/#/liquidity/{continuous_market}")
change_keys(page,vega, "market_maker")
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
change_keys(page, vega, "market_maker")
row = page.get_by_test_id(
"tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Active"
)
@@ -82,4 +95,3 @@ def test_liquidity_provision_inactive(continuous_market, vega: VegaService, page
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -12,6 +12,7 @@ def vega():
with init_vega() as vega:
yield vega
@pytest.fixture(scope="class")
def create_settled_market(vega: VegaService):
market_id = setup_continuous_market(vega)
@@ -73,8 +74,9 @@ class TestSettledMarket:
# 6001-MARK-010
pattern = r"(\d+)\s+(months|hours|days)\s+ago"
date_text = row_selector.locator('[col-id="settlementDate"]').inner_text()
assert re.match(pattern, date_text), f"Expected text to match pattern but got {date_text}"
assert re.match(
pattern, date_text
), f"Expected text to match pattern but got {date_text}"
expected_pattern = re.compile(r"https://.*?/oracles/[a-f0-9]{64}")
actual_href = row_selector.locator(
@@ -87,12 +89,12 @@ class TestSettledMarket:
expect(row_selector.locator('[col-id="bestBidPrice"]')).to_have_text("0.00")
# 6001-MARK-012
expect(row_selector.locator('[col-id="bestOfferPrice"]')).to_have_text("0.00")
# 6001-MARK-013
# 6001-MARK-013
expect(row_selector.locator('[col-id="markPrice"]')).to_have_text("110.00")
# 6001-MARK-014
# 6001-MARK-015
# 6001-MARK-016
#tbd currently we have value unknown
# tbd currently we have value unknown
# expect(row_selector.locator('[col-id="settlementDataOracleId"]')).to_have_text(
# "110.00"
# )
@@ -107,7 +109,9 @@ class TestSettledMarket:
# 6001-MARK-018
expect(row_selector.locator('[col-id="settlementAsset"]')).to_have_text("tDAI")
# 6001-MARK-020
assert re.match(pattern, date_text), f"Expected text to match pattern but got {date_text}"
assert re.match(
pattern, date_text
), f"Expected text to match pattern but got {date_text}"
@pytest.mark.usefixtures("risk_accepted", "auth")
+15 -9
View File
@@ -31,7 +31,7 @@ initial_spread: float = 0.1
market_name = "BTC:DAI_2023"
@pytest.mark.usefixtures("vega", "page", "simple_market", "risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_price_monitoring(simple_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/all")
expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text(
@@ -75,7 +75,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
#6002-MDET-009
# 6002-MDET-009
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("0.00 (0.00%)")
@@ -154,7 +154,7 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.wait_for_total_catchup()
expect(
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
"135.44204 BTC"
@@ -191,22 +191,28 @@ def test_price_monitoring(simple_market, vega: VegaService, page: Page):
)
# commented out because we have an issue #4233
# expect(page.get_by_text("Opening auction")).to_be_hidden()
#6002-MDET-009
# 6002-MDET-009
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("50.00 (>100%)")
COL_ID_FEE = ".ag-center-cols-container [col-id='fee'] .ag-cell-value"
@pytest.mark.usefixtures("vega", "page", "continuous_market", "risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_auction_uncross_fees(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Fills").click()
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
page.locator(COL_ID_FEE).hover()
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI")
change_keys(page,vega, "market_maker")
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
"If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
)
change_keys(page, vega, "market_maker")
expect(page.locator(COL_ID_FEE)).to_have_text("0.00 tDAI")
page.locator(COL_ID_FEE).hover()
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text("If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI")
expect(page.get_by_test_id("fee-breakdown-tooltip")).to_have_text(
"If the market was suspendedIf the market is in monitoring auction, half of the infrastructure and liquidity fees will be paid.Infrastructure fee0.00 tDAILiquidity fee0.00 tDAIMaker fee0.00 tDAITotal fees0.00 tDAI"
)
@@ -3,7 +3,6 @@ import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from fixtures.market import setup_continuous_market
from conftest import init_page, init_vega, risk_accepted_setup
market_title_test_id = "accordion-title"
@@ -15,7 +14,6 @@ def vega():
yield vega
# setting up everything in this single fixture, as all of the tests need the same setup, so no point in creating separate ones
@pytest.fixture(scope="module")
def page(vega, browser, request, local_server):
with init_page(vega, browser, request, local_server) as page:
@@ -122,7 +120,9 @@ def test_market_info_instrument(page: Page):
# @pytest.mark.skip("oracle test to be fixed")
def test_market_info_oracle(page: Page, vega: VegaService):
def test_market_info_oracle(page: Page):
# 6002-MDET-203
page.get_by_test_id(market_title_test_id).get_by_text("Oracle").click()
expect(
@@ -2,7 +2,7 @@ import pytest
from playwright.sync_api import expect, Page
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_market_selector(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
expect(page.get_by_test_id("market-selector")).not_to_be_visible()
@@ -27,7 +27,7 @@ def test_market_selector(continuous_market, page: Page):
expect(btc_market.locator('[data-testid="sparkline-svg"]')).not_to_be_visible
@pytest.mark.usefixtures("page", "continuous_market", "simple_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("simple_market", "auth", "risk_accepted")
@pytest.mark.parametrize(
"simple_market",
[
@@ -1,6 +1,5 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from conftest import init_page, init_vega, risk_accepted_setup
@@ -5,7 +5,7 @@ from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from conftest import init_vega
from fixtures.market import setup_simple_market
from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET, wallets
from wallet_config import MM_WALLET
row_selector = '[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row'
col_market_id = '[col-id="market"] [data-testid="stack-cell-primary"]'
@@ -16,6 +16,7 @@ def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
def proposed_market(vega: VegaService):
# setup market without liquidity provided
@@ -7,6 +7,7 @@ from conftest import init_vega
from actions.utils import wait_for_toast_confirmation
from wallet_config import MM_WALLET, MM_WALLET2
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
@@ -17,6 +18,7 @@ def vega(request):
def simple_market(vega):
return setup_simple_market(vega)
@pytest.fixture(scope="module")
def setup_market_monitoring_auction(vega: VegaService, simple_market):
vega.submit_liquidity(
@@ -48,12 +50,18 @@ def setup_market_monitoring_auction(vega: VegaService, simple_market):
volume=99,
)
# add orders to provide liquidity
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_BUY", 1, 1)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1)
submit_order(vega,MM_WALLET.name,simple_market, "SIDE_BUY",1,1 + 0.1 / 2,)
submit_order(vega,MM_WALLET.name,simple_market,"SIDE_SELL",1,1 + 0.1 / 2)
submit_order(
vega,
MM_WALLET.name,
simple_market,
"SIDE_BUY",
1,
1 + 0.1 / 2,
)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 1, 1 + 0.1 / 2)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_SELL", 1, 1)
vega.forward("10s")
@@ -71,9 +79,11 @@ def setup_market_monitoring_auction(vega: VegaService, simple_market):
vega.wait_fn(1)
vega.wait_for_total_catchup()
@pytest.mark.usefixtures("page", "risk_accepted", "simple_market", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simple_market, vega: VegaService):
@pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_limit_order(
page: Page, simple_market, vega: VegaService
):
page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-size").clear()
page.get_by_test_id("order-size").type("1")
@@ -82,10 +92,14 @@ def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simp
page.get_by_test_id("order-tif").select_option("Fill or Kill (FOK)")
page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text("This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.")
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
)
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_have_text("Any orders placed now will not trade until the auction ends")
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_have_text(
"Any orders placed now will not trade until the auction ends"
)
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_be_visible()
page.get_by_test_id("order-tif").select_option("Good 'til Cancelled (GTC)")
@@ -103,8 +117,11 @@ def test_market_monitoring_auction_price_volatility_limit_order(page: Page, simp
"BTC:DAI_2023Futr0+1LimitActive110.00GTC"
)
@pytest.mark.usefixtures("page", "risk_accepted", "simple_market", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_market_order(page: Page, simple_market):
@pytest.mark.usefixtures("risk_accepted", "auth", "setup_market_monitoring_auction")
def test_market_monitoring_auction_price_volatility_market_order(
page: Page, simple_market
):
page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-type-Market").click()
page.get_by_test_id("order-size").clear()
@@ -112,8 +129,12 @@ def test_market_monitoring_auction_price_volatility_market_order(page: Page, sim
# 7002-SORD-060
page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text("This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders.")
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_have_text(
"This market is in auction due to high price volatility. Until the auction ends, you can only place GFA, GTT, or GTC limit orders."
)
expect(page.get_by_test_id("deal-ticket-error-message-tif")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_have_text("This market is in auction due to high price volatility. Only limit orders are permitted when market is in auction.")
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_have_text(
"This market is in auction due to high price volatility. Only limit orders are permitted when market is in auction."
)
expect(page.get_by_test_id("deal-ticket-error-message-type")).to_be_visible()
@@ -9,8 +9,7 @@ from actions.utils import next_epoch
from wallet_config import MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET
@pytest.mark.usefixtures("vega", "page", "proposed_market", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 7002-SORD-001
# 7002-SORD-002
@@ -27,8 +26,12 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 6002-MDET-002
expect(page.get_by_test_id("market-expiry")).to_have_text("ExpiryNot time-based")
page.get_by_test_id("market-expiry").hover()
expect(page.get_by_test_id("expiry-tooltip").first).to_have_text("This market expires when triggered by its oracle, not on a set date.View oracle specification")
expect(page.get_by_test_id("expiry-tooltip").first.get_by_test_id("link")).to_have_attribute("href", re.compile('.*'))
expect(page.get_by_test_id("expiry-tooltip").first).to_have_text(
"This market expires when triggered by its oracle, not on a set date.View oracle specification"
)
expect(
page.get_by_test_id("expiry-tooltip").first.get_by_test_id("link")
).to_have_attribute("href", re.compile(".*"))
# 6002-MDET-003
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price0.00")
# 6002-MDET-004
@@ -36,18 +39,30 @@ def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
# 6002-MDET-005
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-")
# 6002-MDET-008
expect(page.get_by_test_id("market-settlement-asset")).to_have_text("Settlement assettDAI")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)")
expect(page.get_by_test_id("market-settlement-asset")).to_have_text(
"Settlement assettDAI"
)
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
"Liquidity supplied 0.00 (0.00%)"
)
page.get_by_test_id("liquidity-supplied").hover()
expect(page.get_by_test_id("liquidity-supplied-tooltip").first).to_have_text("Supplied stake0.00Target stake0.00View liquidity provision tableLearn about providing liquidity")
expect(page.get_by_test_id("liquidity-supplied-tooltip").first.get_by_test_id("link").first).to_have_text("View liquidity provision table")
expect(page.get_by_test_id("liquidity-supplied-tooltip").first).to_have_text(
"Supplied stake0.00Target stake0.00View liquidity provision tableLearn about providing liquidity"
)
expect(
page.get_by_test_id("liquidity-supplied-tooltip")
.first.get_by_test_id("link")
.first
).to_have_text("View liquidity provision table")
# check that market is in proposed state
# 6002-MDET-006
# 6002-MDET-007
# 7002-SORD-061
expect(trading_mode).to_have_text("No trading")
trading_mode.hover()
expect(page.get_by_test_id("trading-mode-tooltip").first).to_have_text("No trading enabled for this market.")
expect(page.get_by_test_id("trading-mode-tooltip").first).to_have_text(
"No trading enabled for this market."
)
expect(market_state).to_have_text("Proposed")
# approve market
@@ -182,4 +197,4 @@ def test_market_closing_banners(page: Page, continuous_market, vega: VegaService
will_close_pattern = r"TRADING ON MARKET BTC:DAI_2023 WILL STOP ON \d+ \w+\nYou will no longer be able to hold a position on this market when it closes in \d+ days \d+ hours\. The final price will be 107\.00 BTC\."
match_result = re.fullmatch(will_close_pattern, page.locator(".grow").inner_text())
assert match_result is not None
"""
"""
@@ -48,8 +48,9 @@ def verify_order_value(
else:
expect(element).to_have_text(expected_text)
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_order_details_are_correctly_displayed(
continuous_market, vega: VegaService, page: Page
):
@@ -8,6 +8,7 @@ from actions.vega import submit_order
logger = logging.getLogger()
# Could be turned into a helper function in the future.
def verify_data_grid(page: Page, data_test_id, expected_pattern):
page.get_by_test_id(data_test_id).click()
@@ -49,9 +50,7 @@ def submit_order(vega: VegaService, wallet_name, market_id, side, volume, price)
)
@pytest.mark.usefixtures(
"vega", "page", "opening_auction_market", "auth", "risk_accepted"
)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_trade_open_order(
opening_auction_market, vega: VegaService, page: Page
):
@@ -80,7 +79,7 @@ def test_limit_order_trade_open_order(
verify_data_grid(page, "Open", expected_open_order)
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_trade_open_position(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
@@ -148,7 +147,7 @@ def test_limit_order_trade_open_position(continuous_market, page: Page):
expect(unrealisedPNL).to_have_text(position["unrealised_pnl"])
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_trade_order_trade_away(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
# Assert that the order is no longer on the orderbook
@@ -6,6 +6,7 @@ from conftest import init_vega
from fixtures.market import setup_simple_market
from wallet_config import MM_WALLET, MM_WALLET2
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
@@ -78,8 +79,9 @@ def verify_prices_descending(page: Page):
prices = [float(price.text_content()) for price in prices_locator.all()]
assert prices == sorted(prices, reverse=True)
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_orderbook_grid_content(setup_market, page: Page):
vega = setup_market[0]
market_id = setup_market[1]
@@ -138,7 +140,7 @@ def test_orderbook_grid_content(setup_market, page: Page):
verify_prices_descending(page)
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_orderbook_resolution_change(setup_market, page: Page):
market_id = setup_market[1]
# 6003-ORDB-008
@@ -188,7 +190,7 @@ def test_orderbook_resolution_change(setup_market, page: Page):
# verify_orderbook_grid(page, resolution[1])
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_orderbook_price_size_copy(setup_market, page: Page):
market_id = setup_market[1]
# 6003-ORDB-009
@@ -206,8 +208,9 @@ def test_orderbook_price_size_copy(setup_market, page: Page):
volume.click()
expect(page.get_by_test_id("order-size")).to_have_value(volume.text_content())
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_orderbook_price_movement(setup_market, page: Page):
vega = setup_market[0]
market_id = setup_market[1]
@@ -13,8 +13,8 @@ from wallet_config import MM_WALLET, MM_WALLET2, TERMINATE_WALLET
row_selector = '[data-testid="tab-funding-payments"] .ag-center-cols-container .ag-row'
col_amount = '[col-id="amount"]'
class TestPerpetuals:
class TestPerpetuals:
@pytest.fixture(scope="class")
def vega(self, request):
with init_vega(request) as vega:
@@ -53,31 +53,33 @@ class TestPerpetuals:
vega.wait_for_total_catchup()
return perps_market
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_profit(self, perps_market, page: Page):
page.goto(f"/#/markets/{perps_market}")
page.goto(f"/#/markets/{perps_market}")
page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("9.00 tDAI")
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_loss(self, perps_market, page: Page, vega):
page.goto(f"/#/markets/{perps_market}")
page.goto(f"/#/markets/{perps_market}")
change_keys(page, vega, "market_maker")
page.get_by_test_id("Funding payments").click()
row = page.locator(row_selector)
expect(row.locator(col_amount)).to_have_text("-27.00 tDAI")
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_header(self, perps_market, page: Page):
page.goto(f"/#/markets/{perps_market}")
expect(page.get_by_test_id("market-funding")).to_contain_text("Funding Rate / Countdown-8.1818%")
expect(page.get_by_test_id("market-funding")).to_contain_text(
"Funding Rate / Countdown-8.1818%"
)
expect(page.get_by_test_id("index-price")).to_have_text("Index Price110.00")
@pytest.mark.skip("Skipped due to issue #5421")
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_funding_payment_history(perps_market, page: Page, vega):
page.goto(f"/#/markets/{perps_market}")
page.goto(f"/#/markets/{perps_market}")
change_keys(page, vega, "market_maker")
page.get_by_test_id("Funding history").click()
element = page.get_by_test_id("tab-funding-history")
@@ -92,30 +94,36 @@ class TestPerpetuals:
else:
print("Bounding box not found for the element")
@pytest.mark.usefixtures("page","risk_accepted", "auth")
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_perps_market_termination_proposed(page: Page, vega: VegaService):
perpetual_market = setup_perps_market(vega)
page.goto(f"/#/markets/{perpetual_market}")
page.goto(f"/#/markets/{perpetual_market}")
vega.update_market_state(
proposal_key=MM_WALLET.name,
market_id=perpetual_market,
market_state=MarketStateUpdateType.Terminate,
price=100,
vote_closing_time = datetime.now() + timedelta(seconds=15),
vote_enactment_time = datetime.now() + timedelta(seconds=60),
approve_proposal = True,
forward_time_to_enactment = False,
vote_closing_time=datetime.now() + timedelta(seconds=15),
vote_enactment_time=datetime.now() + timedelta(seconds=60),
approve_proposal=True,
forward_time_to_enactment=False,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
banner_text = page.get_by_test_id(f"termination-warning-banner-{perpetual_market}").text_content()
banner_text = page.get_by_test_id(
f"termination-warning-banner-{perpetual_market}"
).text_content()
pattern = re.compile(
r"Trading on Market BTC:DAI_Perpetual may stop on \d{2} [A-Za-z]+\. There is open proposal to close this market\.Proposed final price is 100\.00 BTC\.View proposal"
r"Trading on Market BTC:DAI_Perpetual may stop on \d{2} [A-Za-z]+\. There is open proposal to close this market\.Proposed final price is 100\.00 BTC\.View proposal"
)
assert pattern.search(banner_text), f"Text did not match pattern. Text was: {banner_text}"
assert pattern.search(
banner_text
), f"Text did not match pattern. Text was: {banner_text}"
@pytest.mark.usefixtures("page","risk_accepted", "auth" )
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_perps_market_terminated(page: Page, vega: VegaService):
perpetual_market = setup_perps_market(vega)
vega.update_market_state(
@@ -123,21 +131,29 @@ def test_perps_market_terminated(page: Page, vega: VegaService):
market_id=perpetual_market,
market_state=MarketStateUpdateType.Terminate,
price=100,
approve_proposal = True,
forward_time_to_enactment = True,
approve_proposal=True,
forward_time_to_enactment=True,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.goto(f"/#/markets/{perpetual_market}")
# TODO cahnge back to have text once bug #5465 is fixed
page.goto(f"/#/markets/{perpetual_market}")
# TODO change back to have text once bug #5465 is fixed
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price100.00")
expect(page.get_by_test_id("market-change")).to_contain_text("Change (24h)")
expect(page.get_by_test_id("market-volume")).to_contain_text("Volume (24h)")
expect(page.get_by_test_id("market-trading-mode")).to_have_text("Trading modeNo trading")
expect(page.get_by_test_id("market-change")).to_contain_text("Change (24h)-")
expect(page.get_by_test_id("market-volume")).to_contain_text("Volume (24h)-")
expect(page.get_by_test_id("market-trading-mode")).to_have_text(
"Trading modeNo trading"
)
expect(page.get_by_test_id("market-state")).to_have_text("StatusClosed")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text("Liquidity supplied 0.00 (0.00%)")
expect(page.get_by_test_id("market-funding")).to_contain_text("Funding Rate / Countdown")
expect(page.get_by_test_id("liquidity-supplied")).to_have_text(
"Liquidity supplied 0.00 (0.00%)"
)
expect(page.get_by_test_id("market-funding")).to_contain_text(
"Funding Rate / Countdown"
)
expect(page.get_by_test_id("index-price")).to_contain_text("Index Price")
expect(page.get_by_test_id("deal-ticket-error-message-summary")).to_have_text("This market is closed and not accepting orders")
expect(page.get_by_test_id("deal-ticket-error-message-summary")).to_have_text(
"This market is closed and not accepting orders"
)
+9 -3
View File
@@ -4,13 +4,15 @@ from vega_sim.service import VegaService
from actions.vega import submit_order
from actions.utils import change_keys
def check_pnl_color_value(element, expected_color, expected_value):
color = element.evaluate("element => getComputedStyle(element).color")
value = element.inner_text()
assert color == expected_color, f"Unexpected color: {color}"
assert value == expected_value, f"Unexpected value: {value}"
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_pnl(continuous_market, vega: VegaService, page: Page):
page.set_viewport_size({"width": 1748, "height": 977})
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 104.50000)
@@ -59,9 +61,13 @@ def test_pnl(continuous_market, vega: VegaService, page: Page):
key_1_unrealised_pnl = key_1.query_selector('xpath=./div[@col-id="unrealisedPNL"]')
key_1_realised_pnl = key_1.query_selector('xpath=./div[@col-id="realisedPNL"]')
key_mm_unrealised_pnl = key_mm.query_selector('xpath=./div[@col-id="unrealisedPNL"]')
key_mm_unrealised_pnl = key_mm.query_selector(
'xpath=./div[@col-id="unrealisedPNL"]'
)
key_mm_realised_pnl = key_mm.query_selector('xpath=./div[@col-id="realisedPNL"]')
key_mm2_unrealised_pnl = key_mm2.query_selector('xpath=./div[@col-id="unrealisedPNL"]')
key_mm2_unrealised_pnl = key_mm2.query_selector(
'xpath=./div[@col-id="unrealisedPNL"]'
)
key_mm2_realised_pnl = key_mm2.query_selector('xpath=./div[@col-id="realisedPNL"]')
check_pnl_color_value(key_1_realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_1_unrealised_pnl, "rgb(236, 0, 60)", "-4.00")
@@ -2,30 +2,31 @@ import os
import pytest
from playwright.sync_api import Page, expect
from actions.utils import wait_for_toast_confirmation
@pytest.mark.usefixtures("page", "auth", "risk_accepted", "continuous_market")
#TODO migrate to jest
@pytest.mark.usefixtures("auth", "risk_accepted", "continuous_market")
def test_ledger_entries_downloads(page: Page):
page.goto("/#/portfolio")
page.get_by_test_id("Ledger entries").click()
expect(page.get_by_test_id("ledger-download-button")).to_be_enabled()
# 7007-LEEN-001
page.get_by_test_id("ledger-download-button").click()
#7007-LEEN-009
# 7007-LEEN-009
expect(page.get_by_test_id("toast-content")).to_contain_text(("Your file is ready"))
# Get the user's Downloads directory
downloads_directory = os.path.expanduser("~") + "/Downloads/"
# Start waiting for the download
with page.expect_download() as download_info:
# Perform the action that initiates download
# Perform the action that initiates download
page.get_by_role("link", name="Get file here").click()
download = download_info.value
# Wait for the download process to complete and save the downloaded file in the Downloads directory
download.save_as(os.path.join(downloads_directory, download.suggested_filename))
# Verify the download by asserting that the file exists
downloaded_file_path = os.path.join(downloads_directory, download.suggested_filename)
assert os.path.exists(downloaded_file_path), f"Download failed! File not found at: {downloaded_file_path}"
downloaded_file_path = os.path.join(
downloads_directory, download.suggested_filename
)
assert os.path.exists(
downloaded_file_path
), f"Download failed! File not found at: {downloaded_file_path}"
@@ -8,44 +8,60 @@ TOOLTIP_LABEL = "margin-health-tooltip-label"
TOOLTIP_VALUE = "margin-health-tooltip-value"
COL_ID_USED = ".ag-center-cols-container [col-id='used'] .ag-cell-value"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
def continuous_market(vega: VegaService):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_usage_breakdown(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Collateral").click()
page.locator(".ag-floating-top-container .ag-row [col-id='used']").click()
usage_breakdown = page.get_by_test_id('usage-breakdown')
usage_breakdown = page.get_by_test_id("usage-breakdown")
# Verify headers
headers = ['Market', 'Account type', 'Balance', 'Margin health']
ag_headers = usage_breakdown.locator('.ag-header-cell-text').element_handles()
headers = ["Market", "Account type", "Balance", "Margin health"]
ag_headers = usage_breakdown.locator(".ag-header-cell-text").element_handles()
for i, header_element in enumerate(ag_headers):
header_text = header_element.text_content()
assert header_text == headers[i]
# Other expectations
expect(usage_breakdown.locator('[class="mb-2 text-sm"]')).to_have_text("You have 1,000,000.00 tDAI in total.")
expect(usage_breakdown.locator('[class="mb-2 text-sm"]')).to_have_text(
"You have 1,000,000.00 tDAI in total."
)
expect(usage_breakdown.locator(COL_ID_USED).first).to_have_text("8.50269 (0%)")
expect(usage_breakdown.locator(COL_ID_USED).nth(1)).to_have_text("999,991.49731 (99%)")
expect(usage_breakdown.locator(COL_ID_USED).nth(1)).to_have_text(
"999,991.49731 (99%)"
)
# Maintenance Level
expect(usage_breakdown.locator(".ag-center-cols-container [col-id='market.id'] .ag-cell-value").first).to_have_text("2.85556 above maintenance level")
expect(
usage_breakdown.locator(
".ag-center-cols-container [col-id='market.id'] .ag-cell-value"
).first
).to_have_text("2.85556 above maintenance level")
# Margin health tooltip
usage_breakdown.get_by_test_id("margin-health-chart-track").hover()
tooltip_data = [("maintenance level", "5.64713"), ("search level", "6.21184"), ("initial level", "8.47069"), ("balance", "8.50269"), ("release level", "9.60012")]
tooltip_data = [
("maintenance level", "5.64713"),
("search level", "6.21184"),
("initial level", "8.47069"),
("balance", "8.50269"),
("release level", "9.60012"),
]
for index, (label, value) in enumerate(tooltip_data):
expect(page.get_by_test_id(TOOLTIP_LABEL).nth(index)).to_have_text(label)
expect(page.get_by_test_id(TOOLTIP_VALUE).nth(index)).to_have_text(value)
page.get_by_test_id('dialog-close').click()
page.get_by_test_id("dialog-close").click()
@@ -5,6 +5,7 @@ from fixtures.market import (
setup_continuous_market,
)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_closed_market_position(vega: VegaService, page: Page):
market_id = setup_continuous_market(vega)
@@ -26,4 +27,3 @@ def test_closed_market_position(vega: VegaService, page: Page):
expect(market.get_by_test_id("stack-cell-primary")).to_have_text("BTC:DAI_2023")
page.get_by_test_id("open-transfer").click()
expect(page.locator(".ag-overlay-panel")).to_have_text("No positions")
@@ -9,10 +9,9 @@ def vega():
yield vega
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_share_usage_data(page: Page):
page.goto("/")
# page.get_by_test_id("icon-cross").click()
page.get_by_test_id("Settings").click()
telemetry_switch = page.locator("#switch-settings-telemetry-switch")
expect(telemetry_switch).to_have_attribute("data-state", "unchecked")
@@ -41,7 +40,7 @@ ICON_TO_TOAST = {
}
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_toast_positions(page: Page):
page.goto("/")
page.get_by_test_id("Settings").click()
@@ -52,7 +51,7 @@ def test_toast_positions(page: Page):
expect(page.locator(f"[{toast_selector}]")).to_be_visible()
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_dark_mode(page: Page):
page.goto("/")
page.get_by_test_id("Settings").click()
@@ -5,7 +5,7 @@ from fixtures.market import setup_continuous_market, setup_simple_successor_mark
@pytest.fixture
@pytest.mark.usefixtures("vega")
@pytest.mark.usefixtures()
def successor_market(vega: VegaService):
parent_market_id = setup_continuous_market(vega)
tdai_id = vega.find_asset_id(symbol="tDAI")
@@ -23,8 +23,7 @@ def successor_market(vega: VegaService):
return successor_market_id
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_succession_line(page: Page, successor_market):
page.goto(f"/#/markets/{successor_market}")
page.get_by_test_id("Info").click()
@@ -45,8 +45,10 @@ def verify_data_grid(page: Page, data_test_id, expected_pattern):
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_limit_order_new_trade_top_of_list(continuous_market, vega: VegaService, page: Page):
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_limit_order_new_trade_top_of_list(
continuous_market, vega: VegaService, page: Page
):
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 110)
vega.wait_fn(1)
vega.wait_for_total_catchup()
@@ -67,7 +69,7 @@ def test_limit_order_new_trade_top_of_list(continuous_market, vega: VegaService,
verify_data_grid(page, "Trades", expected_trade)
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_price_copied_to_deal_ticket(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Trades").click()
@@ -4,10 +4,9 @@ from vega_sim.service import VegaService
from actions.vega import submit_multiple_orders
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures(
"page", "vega", "opening_auction_market", "auth", "risk_accepted"
)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_trade_match_table(opening_auction_market: str, vega: VegaService, page: Page):
row_locator = ".ag-center-cols-container .ag-row"
page.goto(f"/#/markets/{opening_auction_market}")
@@ -12,7 +12,7 @@
# InfoItem = namedtuple('InfoItem', ['name', 'infoText'])
# @pytest.mark.skip("temporary skip")
# @pytest.mark.parametrize("vega", [120], indirect=True)
# @pytest.mark.parametrize(, [120], indirect=True)
# @pytest.mark.usefixtures("continuous_market","risk_accepted", "auth")
# def test_trading_chart(continuous_market, vega: VegaService, page: Page):
# page.goto(f"/#/markets/{continuous_market}")
@@ -2,7 +2,13 @@ import pytest
import re
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.utils import wait_for_toast_confirmation, create_and_faucet_wallet, WalletConfig, next_epoch, change_keys
from actions.utils import (
wait_for_toast_confirmation,
create_and_faucet_wallet,
WalletConfig,
next_epoch,
change_keys,
)
import vega_sim.proto.vega as vega_protos
LIQ = WalletConfig("liq", "liq")
@@ -10,7 +16,8 @@ PARTY_A = WalletConfig("party_a", "party_a")
PARTY_B = WalletConfig("party_b", "party_b")
PARTY_C = WalletConfig("party_c", "party_c")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
# 1003-TRAN-001
# 1003-TRAN-006
@@ -19,38 +26,50 @@ def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
# 1003-TRAN-009
# 1003-TRAN-010
# 1003-TRAN-023
page.goto('/#/portfolio')
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)
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.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}")
actual_asset_text = page.get_by_test_id('select-asset').text_content().strip()
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}"
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] 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")
vega.wait_fn(1)
vega.wait_for_total_catchup()
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}"
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):
@pytest.mark.usefixtures("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()
@@ -94,28 +113,34 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
vega.wait_for_total_catchup()
next_epoch(vega=vega)
next_epoch(vega=vega)
page.goto('/#/portfolio')
expect(page.get_by_test_id('transfer-form')).to_be_visible
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()
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")
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)
page.select_option(
'[data-testid="transfer-form"] [name="fromAccount"]', option_value
)
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('0.000001')
page.locator('[data-testid=transfer-form] input[name="amount"]').fill("0.000001")
page.locator('[data-testid=transfer-form] [type="submit"]').click()
expect(page.get_by_test_id('input-error-text')).to_be_visible
expect(page.get_by_test_id('input-error-text')).to_have_text("Amount below minimum requirements for partial transfer. Use max to bypass")
expect(page.get_by_test_id("input-error-text")).to_be_visible
expect(page.get_by_test_id("input-error-text")).to_have_text(
"Amount below minimum requirements for partial transfer. Use max to bypass"
)
vega.one_off_transfer(
from_key_name=PARTY_B.name,
to_key_name=PARTY_B.name,
from_account_type= vega_protos.vega.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
to_account_type= vega_protos.vega.AccountType.ACCOUNT_TYPE_GENERAL,
asset= asset_id,
amount= 24.999999,
from_account_type=vega_protos.vega.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
to_account_type=vega_protos.vega.AccountType.ACCOUNT_TYPE_GENERAL,
asset=asset_id,
amount=24.999999,
)
vega.forward("10s")
vega.wait_fn(10)
@@ -127,6 +152,10 @@ def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, pa
vega.forward("10s")
vega.wait_fn(1)
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}"
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}"
+63 -45
View File
@@ -15,6 +15,7 @@ tif = "order-tif"
expire = "expire"
api_request_match = r"http://localhost:\d+/api/v2/requests"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
@@ -25,50 +26,59 @@ def vega(request):
def continuous_market(vega):
return setup_continuous_market(vega)
def handle_route_connection_lost(route: Route, request):
if request.method == "POST" and re.match(api_request_match, request.url):
route.fulfill(
status=200,
headers={"Content-Type": "application/json"},
body='{"jsonrpc": "2.0", "id": "1"}'
)
else:
route.continue_()
if request.method == "POST" and re.match(api_request_match, request.url):
route.fulfill(
status=200,
headers={"Content-Type": "application/json"},
body='{"jsonrpc": "2.0", "id": "1"}',
)
else:
route.continue_()
def handle_route_connection_rejected(route: Route, request):
if request.method == "POST" and re.match(api_request_match, request.url):
custom_response = {
"jsonrpc": "2.0",
"error": {
"code": 3001,
"data": "the user rejected the wallet connection",
"message": "User error"
},
"id": "0"
}
route.fulfill(
status=400,
headers={"Content-Type": "application/json"},
body=json.dumps(custom_response)
)
else:
route.continue_()
if request.method == "POST" and re.match(api_request_match, request.url):
custom_response = {
"jsonrpc": "2.0",
"error": {
"code": 3001,
"data": "the user rejected the wallet connection",
"message": "User error",
},
"id": "0",
}
route.fulfill(
status=400,
headers={"Content-Type": "application/json"},
body=json.dumps(custom_response),
)
else:
route.continue_()
def assert_connection_approve(route: Route, request, page:Page):
if request.method == "POST" and re.match(api_request_match, request.url):
expect(page.get_by_test_id("toast-content")).to_have_text("Please go to your Vega wallet application and approve or reject the transaction.")
else:
route.continue_()
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def assert_connection_approve(route: Route, request, page: Page):
if request.method == "POST" and re.match(api_request_match, request.url):
expect(page.get_by_test_id("toast-content")).to_have_text(
"Please go to your Vega wallet application and approve or reject the transaction."
)
else:
route.continue_()
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_error(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.route("**/*", handle_route_connection_lost)
page.get_by_test_id("connect-vega-wallet").click()
page.get_by_test_id("connector-jsonRpc").click()
expect(page.get_by_test_id("wallet-dialog-title")).to_have_text("Something went wrong")
expect(page.get_by_test_id("wallet-dialog-title")).to_have_text(
"Something went wrong"
)
@pytest.mark.usefixtures("page", "risk_accepted")
@pytest.mark.usefixtures("risk_accepted")
def test_wallet_connection_rejected(continuous_market, page: Page):
# 0002-WCON-002
# 0002-WCON-005
@@ -78,11 +88,13 @@ def test_wallet_connection_rejected(continuous_market, page: Page):
page.route("**/*", handle_route_connection_rejected)
page.get_by_test_id("connect-vega-wallet").click()
page.get_by_test_id("connector-jsonRpc").click()
expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text("User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers ")
expect(page.get_by_test_id("dialog-content").nth(1)).to_have_text(
"User errorthe user rejected the wallet connectionTry againAbout the Vega wallet | Supported browsers "
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_wallet_connection_error_transaction(continuous_market, vega: VegaService, page: Page):
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_error_transaction(continuous_market, page: Page):
# 0003-WTXN-009
# 0003-WTXN-011
# 0002-WCON-016
@@ -92,20 +104,26 @@ def test_wallet_connection_error_transaction(continuous_market, vega: VegaServic
page.get_by_test_id(order_price).fill("120")
page.route("**/*", handle_route_connection_lost)
page.get_by_test_id(place_order).click()
expect(page.get_by_test_id("toast-content")).to_have_text("Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_wallet_transaction_rejected(continuous_market, vega: VegaService, page: Page):
expect(page.get_by_test_id("toast-content")).to_have_text(
"Wallet disconnectedThe connection to your Vega Wallet has been lost.Connect vega wallet"
)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_transaction_rejected(continuous_market, page: Page):
# 0003-WTXN-007
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(order_price).fill("120")
page.route("**/*", handle_route_connection_rejected)
page.get_by_test_id(place_order).click()
expect(page.get_by_test_id("toast-content")).to_have_text("Error occurredthe user rejected the wallet connection")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_wallet_connection_approve(continuous_market, vega: VegaService, page: Page):
expect(page.get_by_test_id("toast-content")).to_have_text(
"Error occurredthe user rejected the wallet connection"
)
@pytest.mark.usefixtures("auth", "risk_accepted")
def test_wallet_connection_approve(continuous_market, page: Page):
# 0002-WCON-005
# 0002-WCON-007
# 0002-WCON-009
@@ -113,4 +131,4 @@ def test_wallet_connection_approve(continuous_market, vega: VegaService, page: P
page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(order_price).fill("120")
page.route("**/*", assert_connection_approve)
page.get_by_test_id(place_order).click()
page.get_by_test_id(place_order).click()
@@ -0,0 +1,62 @@
import {
Intent,
useToasts,
ToastHeading,
CLOSE_AFTER,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useEffect, useMemo } from 'react';
import { useT } from '../use-t';
import { VegaWalletConnectButton } from '../../components/vega-wallet-connect-button';
const WALLET_DISCONNECTED_TOAST_ID = 'WALLET_DISCONNECTED_TOAST_ID';
export const useWalletDisconnectedToasts = () => {
const t = useT();
const [hasToast, setToast, updateToast] = useToasts((state) => [
state.hasToast,
state.setToast,
state.update,
]);
const { isAlive } = useVegaWallet();
const toast = useMemo(
() => ({
id: WALLET_DISCONNECTED_TOAST_ID,
intent: Intent.Danger,
content: (
<>
<ToastHeading>{t('Wallet connection lost')}</ToastHeading>
<p>{t('The connection to the Vega wallet has been lost.')}</p>
<p className="mt-2">
<VegaWalletConnectButton
intent={Intent.Danger}
onClick={() => {
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
hidden: true,
});
}}
/>
</p>
</>
),
onClose: () => {
updateToast(WALLET_DISCONNECTED_TOAST_ID, {
hidden: true,
});
},
closeAfter: CLOSE_AFTER,
}),
[t, updateToast]
);
useEffect(() => {
if (isAlive === false) {
if (hasToast(WALLET_DISCONNECTED_TOAST_ID)) {
updateToast(WALLET_DISCONNECTED_TOAST_ID, { hidden: false });
} else {
setToast(toast);
}
}
}, [hasToast, isAlive, setToast, t, toast, updateToast]);
};
+1 -1
View File
@@ -13,7 +13,7 @@ export default function Document() {
{/* preload fonts */}
<link
rel="preload"
href="/AlphaLyrae-Medium.woff2"
href="/AlphaLyrae.woff2"
as="font"
type="font/woff2"
/>
+1 -2
View File
@@ -4,8 +4,7 @@
/** Load AlphaLyrae font */
@font-face {
font-family: AlphaLyrae;
src: url('/AlphaLyrae-Medium.woff2') format('woff2'),
url('/AlphaLyrae-Medium.woff') format('woff');
src: url('/AlphaLyrae.woff2') format('woff2');
}
@tailwind base;
+2
View File
@@ -6,6 +6,7 @@ import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3';
import { useReadyToWithdrawalToasts } from '@vegaprotocol/withdraws';
import { Links } from '../lib/links';
import { useReferralToasts } from '../client-pages/referrals/hooks/use-referral-toasts';
import { useWalletDisconnectedToasts } from '../lib/hooks/use-wallet-disconnected-toasts';
export const ToastsManager = () => {
useProposalToasts();
@@ -16,6 +17,7 @@ export const ToastsManager = () => {
withdrawalsLink: Links.PORTFOLIO(),
});
useReferralToasts();
useWalletDisconnectedToasts();
const toasts = useToasts((store) => store.toasts);
return <ToastsContainer order="desc" toasts={toasts} />;
@@ -76,9 +76,14 @@ export const DealTicketFeeDetails = ({
<KeyValue
label={
<>
{t('Fees')}
<span data-testid="fees-text">{t('Fees')}</span>
{totalDiscountFactor !== '0' ? (
<Pill size="xxs" intent={Intent.Info} className="ml-1">
<Pill
size="xxs"
intent={Intent.Info}
className="ml-1"
data-testid="discount-pill"
>
{formatNumberPercentage(
new BigNumber(totalDiscountFactor).multipliedBy(100)
)}
@@ -23,19 +23,23 @@ const FeesBreakdownItem = ({
value,
symbol,
decimals,
testId,
}: {
label: string;
factor?: string | number;
value: string;
symbol?: string;
decimals: number;
testId?: string;
}) => (
<>
<dt className="col-span-2">{label}</dt>
<dd className="text-right col-span-1">
<dt className="col-span-2" data-testid={`${testId}-label`}>
{label}
</dt>
<dd className="text-right col-span-1" data-testid={`${testId}-factor`}>
{factor ? formatNumberPercentage(new BigNumber(factor).times(100)) : ''}
</dd>
<dd className="text-right col-span-3">
<dd className="text-right col-span-3" data-testid={`${testId}-value`}>
{formatValue(value, decimals)} {symbol || ''}
</dd>
</>
@@ -73,6 +77,7 @@ export const FeesBreakdown = ({
value={fees.infrastructureFee}
symbol={symbol}
decimals={decimals}
testId="infrastructure-fee"
/>
<FeesBreakdownItem
@@ -81,6 +86,7 @@ export const FeesBreakdown = ({
value={fees.liquidityFee}
symbol={symbol}
decimals={decimals}
testId="liquidity-fee"
/>
<FeesBreakdownItem
@@ -89,6 +95,7 @@ export const FeesBreakdown = ({
value={fees.makerFee}
symbol={symbol}
decimals={decimals}
testId="maker-fee"
/>
{totalDiscount && totalDiscount !== '0' ? (
<>
@@ -100,6 +107,7 @@ export const FeesBreakdown = ({
}
symbol={symbol}
decimals={decimals}
testId="subtotal-fee"
/>
<div className="col-span-6 mt-2"></div>
<FeesBreakdownItem
@@ -108,12 +116,14 @@ export const FeesBreakdown = ({
value={`-${totalDiscount}`}
symbol={symbol}
decimals={decimals}
testId="discount-fee"
/>
<FeesBreakdownItem
label={t('Total')}
value={discountedTotalFeeAmount}
symbol={symbol}
decimals={decimals}
testId="total-fee"
/>
</>
) : (
@@ -127,6 +137,7 @@ export const FeesBreakdown = ({
value={totalFeeAmount}
symbol={symbol}
decimals={decimals}
testId="full-total-fee"
/>
</>
)}
+7 -9
View File
@@ -57,6 +57,7 @@
"Current tier": "Current tier",
"Dark mode": "Dark mode",
"Date Joined": "Date Joined",
"Depending on data node retention you may not be able see the full 30 days": "Depending on data node retention you may not be able see the full 30 days",
"Deposit": "Deposit",
"Deposit funds": "Deposit funds",
"Deposits": "Deposits",
@@ -224,9 +225,9 @@
"Referral benefits": "Referral benefits",
"Referral discount": "Referral discount",
"Referrals": "Referrals",
"referralStatisticsCommission": "Commission earned in <0>qUSD</0> (last {{count}} epochs)",
"referralStatisticsCommission_one": "Commission earned in <0>qUSD</0> (last {{count}} epoch)",
"referralStatisticsCommission_other": "Commission earned in <0>qUSD</0> (last {{count}} epochs)",
"referralStatisticsCommission": "Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)",
"referralStatisticsCommission_one": "Commission earned in <0>qUSD</0> (<1>last {{count}} epoch</1>)",
"referralStatisticsCommission_other": "Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)",
"Referrer commission": "Referrer commission",
"Referrer trading discount": "Referrer trading discount",
"Referrers earn commission based on a percentage of the taker fees their referees pay": "Referrers earn commission based on a percentage of the taker fees their referees pay",
@@ -295,9 +296,9 @@
"Total distributed": "Total distributed",
"Total fee after discount": "Total fee after discount",
"Total fee before discount": "Total fee before discount",
"totalCommission": "Total commission (last {{count}}} epochs)",
"totalCommission_one": "Total commission (last {{count}}} epoch)",
"totalCommission_other": "Total commission (last {{count}}} epochs)",
"totalCommission": "Total commission (<0>last {{count}} epochs</0>)",
"totalCommission_one": "Total commission (<0>last {{count}} epoch</0>)",
"totalCommission_other": "Total commission (<0>last {{count}} epochs</0>)",
"Trader": "Trader",
"Trades": "Trades",
"Trading": "Trading",
@@ -308,9 +309,6 @@
"Trading on Market {{name}} may stop. There are open proposals to close this market": "Trading on Market {{name}} may stop. There are open proposals to close this market",
"Trading on Market {{name}} will stop on {{date}}": "Trading on Market {{name}} will stop on {{date}}",
"Transfer": "Transfer",
"totalCommission": "Total commission (last {{count}} epochs)",
"totalCommission_one": "Total commission (last {{count}} epoch)",
"totalCommission_other": "Total commission (last {{count}} epochs)",
"Unknown": "Unknown",
"Unknown settlement date": "Unknown settlement date",
"Vega chart": "Vega chart",
@@ -68,13 +68,10 @@ export const useBlockRising = (skip = false) => {
}
);
const heights = compact([...results.map((r) => r?.blockHeight)]);
// Handles TendermintErrorResponses
if (blockInfo && 'result' in blockInfo) {
heights.push(blockInfo.result.block.header.height);
}
const heights = compact([
...results.map((r) => r?.blockHeight),
blockInfo?.result.block.header.height,
]);
const current = max(heights);
if (current && Number(current) > prev) {
setBlock(Number(current));
+3 -13
View File
@@ -76,26 +76,16 @@ export const useFetch = <T>(
...options,
body: body ? body : options?.body,
});
data = (await response.json()) as T;
if (!response.ok && !data) {
if (!response.ok) {
throw new Error(response.statusText);
}
data = (await response.json()) as T;
// @ts-ignore - 'error' in data
if (data && data.error) {
// Explicit check for TendermintErrorResponse style error
// @ts-ignore - 'error' in data
if (data.error.data) {
// @ts-ignore - 'error' in data
throw new Error(data.error.data);
}
if (data && 'error' in data) {
// @ts-ignore - data.error
throw new Error(data.error);
}
if (cancelRequest.current) return;
dispatch({ type: ActionType.FETCHED, payload: data });
+2 -7
View File
@@ -1,11 +1,6 @@
import { useEnvironment } from '@vegaprotocol/environment';
import { useFetch } from '@vegaprotocol/react-helpers';
import type {
TendermintBlockResponse,
TendermintErrorResponse,
} from '../types';
type TendermintResponse = TendermintBlockResponse | TendermintErrorResponse;
import { type TendermintBlockResponse } from '../types';
export const useBlockInfo = (blockHeight?: number, canFetch = true) => {
const { TENDERMINT_URL } = useEnvironment();
@@ -15,7 +10,7 @@ export const useBlockInfo = (blockHeight?: number, canFetch = true) => {
TENDERMINT_URL && blockHeight && !isNaN(blockHeight) && canFetch
);
const { state, refetch } = useFetch<TendermintResponse>(
const { state, refetch } = useFetch<TendermintBlockResponse>(
url,
{ cache: 'force-cache' },
canFetchData
+1 -11
View File
@@ -7,16 +7,6 @@ export type TendermintBlockResponse = {
};
};
export type TendermintErrorResponse = {
jsonrpc: string;
id: number;
error: {
code: number;
message: string;
data: string;
};
};
type Id = {
hash: string;
parts: {
@@ -44,7 +34,7 @@ type Header = {
proposer_address: string;
};
export type Block = {
type Block = {
header: Header;
data: {
txs: string[];
@@ -68,6 +68,19 @@ export class InjectedConnector implements VegaConnector {
return res.keys;
}
async isAlive() {
try {
const keys = await window.vega.listKeys();
if (keys.keys.length > 0) {
return true;
}
} catch (err) {
return false;
}
return false;
}
disconnect() {
clearConfig();
return window.vega.disconnectWallet();
@@ -123,12 +123,31 @@ export class JsonRpcConnector implements VegaConnector {
}
}
async isAlive() {
if (this.client) {
try {
const keys = await this.client.ListKeys();
if (keys.result.keys.length > 0) {
return true;
}
} catch (err) {
return false;
}
}
return false;
}
async disconnect() {
if (!this.client) {
throw ClientErrors.NO_CLIENT;
}
await this.client.DisconnectWallet();
try {
await this.client.DisconnectWallet();
} catch (err) {
// NOOP
}
clearConfig();
}
@@ -167,6 +167,19 @@ export class SnapConnector implements VegaConnector {
return res?.keys;
}
async isAlive() {
try {
const keys = await this.listKeys();
if (keys.keys.length > 0) {
return true;
}
} catch (err) {
return false;
}
return false;
}
async sendTx(pubKey: string, transaction: Transaction) {
if (!this.nodeAddress) throw SnapConnectorErrors.NODE_ADDRESS_NOT_SET;
if (!this.snapId) throw SnapConnectorErrors.SNAP_ID_NOT_SET;
@@ -543,4 +543,9 @@ export interface VegaConnector {
pubkey: string,
transaction: Transaction
) => Promise<TransactionResponse | null>;
/**
* Checks if the connection to the connector is alive.
*/
isAlive: () => Promise<boolean>;
}
@@ -39,6 +39,11 @@ export class ViewConnector implements VegaConnector {
},
]);
}
async isAlive() {
return true;
}
disconnect(): Promise<void> {
clearConfig();
this.pubkey = null;
+5
View File
@@ -56,6 +56,11 @@ export interface VegaWalletContextShape {
chromeExtensionUrl: string;
mozillaExtensionUrl: string;
};
/**
* A flag determining whether the current connection is alive.
*/
isAlive: boolean | null;
}
export const VegaWalletContext = createContext<
+27 -1
View File
@@ -1,4 +1,4 @@
import { act, renderHook } from '@testing-library/react';
import { act, renderHook, waitFor } from '@testing-library/react';
import type { Transaction } from './connectors';
import { ViewConnector, JsonRpcConnector } from './connectors';
import { useVegaWallet } from './use-vega-wallet';
@@ -7,6 +7,7 @@ import { VegaWalletProvider } from './provider';
import { LocalStorage } from '@vegaprotocol/utils';
import type { ReactNode } from 'react';
import { WALLET_KEY } from './storage';
import { DEFAULT_KEEP_ALIVE } from './use-is-alive';
const jsonRpcConnector = new JsonRpcConnector();
const viewConnector = new ViewConnector();
@@ -35,6 +36,7 @@ const setup = (config?: Partial<VegaWalletConfig>) => {
describe('VegaWalletProvider', () => {
afterAll(() => {
localStorage.clear();
jest.useRealTimers();
});
const mockPubKeys = [
@@ -81,6 +83,7 @@ describe('VegaWalletProvider', () => {
browserList: expect.any(String),
...defaultConfig.links,
},
isAlive: null,
});
// Connect
@@ -179,4 +182,27 @@ describe('VegaWalletProvider', () => {
});
expect(result.current.isReadOnly).toBe(true);
});
it('sets isAlive to false if connection lost', async () => {
// setup and connect
jest.useFakeTimers();
jest
.spyOn(jsonRpcConnector, 'isAlive')
.mockImplementation(() => Promise.resolve(true));
const { result } = setup();
await act(async () => {
result.current.connect(jsonRpcConnector);
});
expect(result.current.isAlive).toEqual(null);
// loose connection
jest
.spyOn(jsonRpcConnector, 'isAlive')
.mockImplementation(() => Promise.resolve(false));
jest.advanceTimersByTime(DEFAULT_KEEP_ALIVE);
await waitFor(() => {
expect(result.current.isAlive).toEqual(false);
});
});
});
+25 -1
View File
@@ -1,5 +1,12 @@
import { LocalStorage } from '@vegaprotocol/utils';
import { useCallback, useMemo, useRef, useState, type ReactNode } from 'react';
import {
useCallback,
useMemo,
useRef,
useState,
type ReactNode,
useEffect,
} from 'react';
import { WalletClientError } from '@vegaprotocol/wallet-client';
import { type VegaWalletContextShape } from '.';
import {
@@ -11,6 +18,7 @@ import { VegaWalletContext } from './context';
import { WALLET_KEY, WALLET_RISK_ACCEPTED_KEY } from './storage';
import { ViewConnector } from './connectors';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { DEFAULT_KEEP_ALIVE, useIsAlive } from './use-is-alive';
type Networks =
| 'MAINNET'
@@ -33,6 +41,7 @@ export interface VegaWalletConfig {
vegaUrl: string;
vegaWalletServiceUrl: string;
links: VegaWalletLinks;
keepAlive?: number;
}
const ExternalLinks = {
@@ -143,6 +152,19 @@ export const VegaWalletProvider = ({
const acknowledgeNeeded =
config.network === 'MAINNET' && riskAcceptedValue !== 'true';
const isAlive = useIsAlive(
connector.current && pubKey ? connector.current : null,
config.keepAlive != null ? config.keepAlive : DEFAULT_KEEP_ALIVE
);
/**
* Force disconnect if connected and wallet is unreachable.
*/
useEffect(() => {
if (isAlive === false) {
disconnect();
}
}, [disconnect, isAlive]);
const contextValue = useMemo<VegaWalletContextShape>(() => {
return {
vegaUrl: config.vegaUrl,
@@ -165,6 +187,7 @@ export const VegaWalletProvider = ({
sendTx,
fetchPubKeys,
acknowledgeNeeded,
isAlive,
};
}, [
config,
@@ -177,6 +200,7 @@ export const VegaWalletProvider = ({
sendTx,
fetchPubKeys,
acknowledgeNeeded,
isAlive,
]);
return (
+31
View File
@@ -0,0 +1,31 @@
import { useEffect, useState } from 'react';
import { type VegaConnector } from '.';
/**
* Determines the interval for checking if wallet connection is alive.
*/
export const DEFAULT_KEEP_ALIVE = 1000;
export const useIsAlive = (
connector: VegaConnector | null,
interval: number
) => {
const [alive, setAlive] = useState<boolean | null>(null);
useEffect(() => {
if (!connector) {
return;
}
const i = setInterval(() => {
connector.isAlive().then((isAlive) => {
if (alive !== isAlive) setAlive(isAlive);
});
}, interval);
return () => {
clearInterval(i);
};
}, [alive, connector, interval]);
return alive;
};