chore(trading): add playwright and market sim testing framework (#5199)

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: dalebennett1992 <dalebennett1992@hotmail.co.uk>
This commit is contained in:
Ben 2023-11-14 18:05:07 +00:00 committed by GitHub
parent 06769f25cf
commit 02c425f304
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 7213 additions and 24 deletions

View File

@ -205,7 +205,7 @@ jobs:
console-e2e:
needs: [build-sources, check-e2e-needed]
name: '(CI) console python'
name: '(CI) trading e2e python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')

View File

@ -10,7 +10,7 @@ on:
inputs:
console-test-branch:
type: choice
description: 'main: v0.72.14, develop: v0.73.0-preview7'
description: 'main: v0.72.14, develop: v0.73.4'
options:
- main
- develop
@ -153,25 +153,19 @@ jobs:
run: |
docker load --input /tmp/console-image.tar
docker image ls -a
#----------------------------------------------
# check-out tests repo
# check-out frontend-monorepo
#----------------------------------------------
- name: Checkout console test repo
- name: Checkout frontend-monorepo
uses: actions/checkout@v3
with:
repository: vegaprotocol/console-test
ref: ${{ needs.console-test-branch.outputs.console-branch }}
- name: Load console test envs
id: console-test-env
uses: falti/dotenv-action@v1.0.4
with:
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
export-variables: true
keys-case: upper
log-variables: true
ref: ${{ inputs.github-sha || github.sha }}
#----------------------------------------------
# get vega version
#----------------------------------------------
- name: Set VEGA_VERSION from .env
id: set_vega_version
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
#----------------------------------------------
# ----- Setup python -----
#----------------------------------------------
@ -194,22 +188,25 @@ jobs:
#----------------------------------------------
- name: Install dependencies
run: poetry install --no-interaction --no-root
working-directory: apps/trading/e2e
#----------------------------------------------
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
working-directory: apps/trading/e2e
#----------------------------------------------
# install playwright
# install playwrightworking-directory: apps/trading/e2e
#----------------------------------------------
- name: install playwright
run: poetry run playwright install --with-deps chromium
working-directory: apps/trading/e2e
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
working-directory: apps/trading/e2e
#----------------------------------------------
# upload traces
#----------------------------------------------

9
.gitignore vendored
View File

@ -53,4 +53,11 @@ cypress.env.json
/apps/**/cypress/downloads/
/apps/**/fixtures/wallet/node**
.nx/cache
#console-test
__pycache__/
apps/trading/e2e/logs/
apps/trading/e2e/.pytest_cache/
apps/trading/e2e/traces/
.nx/cache

2
apps/trading/e2e/.env Normal file
View File

@ -0,0 +1,2 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
VEGA_VERSION=v0.73.4

View File

@ -0,0 +1,2 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
VEGA_VERSION=v0.73.4

View File

@ -0,0 +1,2 @@
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
VEGA_VERSION=v0.73.4

136
apps/trading/e2e/README.md Normal file
View File

@ -0,0 +1,136 @@
# Trading Market-Sim End-To-End Tests
This direcotry contains end-to-end tests for the trading application using vega-market-sim. This README will guide you through setting up your environment and running the tests.
## Prerequisites
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
- [Docker](https://www.docker.com/)
- [Python versions ">=3.9,<3.11"](https://www.python.org/)
## Getting Started
1. **Install Poetry**: Follow the instructions on the [official Poetry website](https://python-poetry.org/docs/#installing-with-the-official-installer).
2. **Install Docker**: Follow the instructions on the [official Docker website](https://docs.docker.com/desktop/).
3. **Install Python**: Follow the instructions on the [official Python website](https://www.python.org/)
**ensure you install a version between 3.9 and 3.11.**
4. **Start up a Poetry environment**: Execute the commands below to configure the Poetry environment.
### Ensure you are in the tests folder before running commands
```bash
poetry shell
```
5. **Install python dependencies**
```bash
poetry install
```
6. **Install Playwright Browsers**: Execute the command below to browsers for Playwright.
```bash
playwright install chromium
```
7. **Download necessary binaries**:
Use the following command within your Python environment. The `--force` flag ensures the binaries are overwritten, and the `--version` specifies the desired version. e.g. `v0.73.4`
```bash
python -m vega_sim.tools.load_binaries --force --version $VEGA_VERSION
```
8. **Pull the desired Docker image**
```bash
docker pull vegaprotocol/trading:develop
```
9. **Run tests**: Poetry/Python will serve the app from docker
### Update the .env file with the correct trading image.
```bash
poetry run pytest
```
### Docker images
Pull the desired image:
**Testnet**
```bash
docker pull vegaprotocol/trading:develop
```
**Mainnet**
```bash
docker pull vegaprotocol/trading:main
```
Find all available images on [Docker Hub](https://hub.docker.com/r/vegaprotocol/trading/tags).
#### Create a Docker Image of Your Locally Built Trading App
To build your Docker image, use the following commands:
```bash
yarn nx build trading ./docker/prepare-dist.sh
```
```bash
docker build -f docker/node-outside-docker.Dockerfile --build-arg APP=trading --build-arg ENV_NAME=stagnet1 -t vegaprotocol/trading:latest .
```
## Running Tests 🧪
Before running make sure the docker daemon is runnign so that the app can be served.
To run a specific test, use the `-k` option followed by the name of the test.
Run all tests:
```bash
poetry run pytest
```
Run a targeted test:
```bash
poetry run pytest -k "test_name" -s
```
Run from anywhere:
```bash
yarn trading:test -- "test_name" -s
```
## Running Tests in Parallel 🔢
To run tests in parallel, use the `--numprocesses auto` option. The `--dist loadfile` setting ensures that multiple runners are not assigned to a single test file.
### From within the e2e folder:
```bash
poetry run pytest -s --numprocesses auto --dist loadfile
```
### From anywhere:
```bash
yarn trading:test:all
```
# Things to know
If you "intellisense" isn't working follow these steps:
1. ```bash
poetry run which python
```
2. Then open the command menu in vscode (cmd + shift + p) and type `select interpreter` , press enter, select enter interpreter path press enter then paste in the output from that above command you should get the right python again

View File

@ -0,0 +1,38 @@
from collections import namedtuple
from playwright.sync_api import Page
from vega_sim.null_service import VegaServiceNull
from typing import Optional
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
ASSET_NAME = "tDAI"
def wait_for_toast_confirmation(page: Page, timeout: int = 30000):
page.wait_for_function("""
document.querySelector('[data-testid="toast-content"]') &&
document.querySelector('[data-testid="toast-content"]').innerText.includes('AWAITING CONFIRMATION')
""", timeout=timeout)
def create_and_faucet_wallet(
vega: VegaServiceNull,
wallet: WalletConfig,
symbol: Optional[str] = None,
amount: float = 1e4,
):
asset_id = vega.find_asset_id(symbol=symbol if symbol is not None else ASSET_NAME)
vega.create_key(wallet.name)
vega.mint(wallet.name, asset_id, amount)
def next_epoch(vega: VegaServiceNull):
forwards = 0
epoch_seq = vega.statistics().epoch_seq
while epoch_seq == vega.statistics().epoch_seq:
vega.wait_fn(1)
forwards += 1
if forwards > 2 * 10 * 60:
raise Exception(
"Epoch not started after forwarding the duration of two epochs."
)
vega.wait_fn(1)
vega.wait_for_total_catchup()

View File

@ -0,0 +1,65 @@
from typing import List, Tuple, Optional
from vega_sim.service import VegaService, PeggedOrder
def submit_order(
vega: VegaService,
wallet_name: str,
market_id: str,
side: str,
volume: float,
price: float,
peak_size: Optional[float] = None,
minimum_visible_size: Optional[float] = None,
):
return vega.submit_order(
trading_key=wallet_name,
market_id=market_id,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side=side,
volume=volume,
price=price,
peak_size=peak_size,
minimum_visible_size=minimum_visible_size,
)
def submit_multiple_orders(
vega: VegaService,
wallet_name: str,
market_id: str,
side: str,
volume_price_pair: List[Tuple[float, float]],
):
for volume, price in volume_price_pair:
submit_order(vega, wallet_name, market_id, side, volume, price)
def submit_liquidity(vega: VegaService, wallet_name: str, market_id: str):
vega.submit_simple_liquidity(
key_name=wallet_name,
market_id=market_id,
commitment_amount=10000,
fee=0.000,
is_amendment=False,
)
vega.submit_order(
market_id=market_id,
trading_key=wallet_name,
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
vega.submit_order(
market_id=market_id,
trading_key=wallet_name,
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)

View File

@ -0,0 +1,9 @@
import os
from dotenv import load_dotenv
load_dotenv()
console_image_name = os.getenv(
"CONSOLE_IMAGE_NAME", default="vegaprotocol/trading:latest"
)
vega_version = os.getenv("VEGA_VERSION", default="latest")

View File

@ -0,0 +1,243 @@
import logging
import pytest
import os
import json
import requests
import time
import docker
import http.server
import socketserver
from threading import Thread
from contextlib import contextmanager
from vega_sim.null_service import VegaServiceNull
from playwright.sync_api import Browser, Page
from config import console_image_name, vega_version
from fixtures.market import (
setup_simple_market,
setup_opening_auction_market,
setup_continuous_market,
)
import sys
# Workaround for current xdist issue with displaying live logs from multiple workers
# https://github.com/pytest-dev/pytest-xdist/issues/402
sys.stdout = sys.stderr
docker_client = docker.from_env()
logger = logging.getLogger()
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call):
outcome = "passed" if call.excinfo is None else "failed"
item.config.cache.set(item.nodeid, outcome)
def pytest_configure(config):
worker_id = os.environ.get("PYTEST_XDIST_WORKER")
if worker_id is not None:
log_dir = os.path.join(os.getcwd(), "logs")
log_name = f"tests_{worker_id}.log"
if not os.path.exists(log_dir):
os.makedirs(log_dir)
logging.basicConfig(
format=config.getini("log_file_format"),
datefmt=config.getini("log_file_date_format"),
filename=os.path.join(log_dir, log_name),
level=config.getini("log_file_level"),
)
class CustomHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
# Set the path to your website's directory here
if self.path == '/':
self.path = 'dist/apps/trading/exported/index.html'
return http.server.SimpleHTTPRequestHandler.do_GET(self)
# Start VegaServiceNull
@contextmanager
def init_vega(request=None):
default_seconds = 1
seconds_per_block = default_seconds
if request and hasattr(request, "param"):
seconds_per_block = request.param
logger.info(
"Starting VegaServiceNull",
extra={"worker_id": os.environ.get("PYTEST_XDIST_WORKER")},
)
logger.info(f"Using console image: {console_image_name}")
logger.info(f"Using vega version: {vega_version}")
with VegaServiceNull(
run_with_console=False,
launch_graphql=False,
retain_log_files=True,
use_full_vega_wallet=True,
store_transactions=True,
transactions_per_block=1000,
seconds_per_block=seconds_per_block,
) as vega:
try:
container = docker_client.containers.run(
console_image_name, detach=True, ports={"80/tcp": vega.console_port}
)
# docker setup
logger.info(
f"Container {container.id} started",
extra={"worker_id": os.environ.get("PYTEST_XDIST_WORKER")},
)
yield vega
except docker.errors.APIError as e:
logger.info(f"Container creation failed.")
logger.info(e)
raise e
finally:
logger.info(f"Stopping container {container.id}")
container.stop()
# Remove the container
logger.info(f"Removing container {container.id}")
container.remove()
@contextmanager
def init_page(vega: VegaServiceNull, browser: Browser, request: pytest.FixtureRequest):
with browser.new_context(
viewport={"width": 1920, "height": 1080},
base_url=f"http://localhost:{vega.console_port}",
) as context, context.new_page() as page:
context.tracing.start(screenshots=True, snapshots=True, sources=True)
try:
# Wait for the console to be up and running before any tests are run
attempts = 0
while attempts < 100:
try:
code = requests.get(
f"http://localhost:{vega.console_port}/"
).status_code
if code == 200:
break
except requests.exceptions.ConnectionError as e:
attempts += 1
if attempts < 100:
time.sleep(0.1)
continue
else:
raise e
# Set window._env_ so built app uses datanode from vega market sim
env = json.dumps(
{
"VEGA_URL": f"http://localhost:{vega.data_node_rest_port}/graphql",
"VEGA_WALLET_URL": f"http://localhost:{vega.wallet_port}",
}
)
window_env = f"window._env_ = Object.assign({{}}, window._env_, {env})"
page.add_init_script(script=window_env)
yield page
finally:
if not os.path.exists("traces"):
os.makedirs("traces")
# Check whether this test failed or passed
outcome = request.config.cache.get(request.node.nodeid, None)
if outcome != "passed":
try:
trace_path = os.path.join("traces", request.node.name + "trace.zip")
context.tracing.stop(path=trace_path)
except Exception as e:
logger.error(f"Failed to save trace: {e}")
@pytest.fixture
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture
def page(vega, browser, request):
with init_page(vega, browser, request) as page_instance:
yield page_instance
# Set auth token so eager connection for MarketSim wallet is successful
def auth_setup(vega: VegaServiceNull, page: Page):
DEFAULT_WALLET_NAME = "MarketSim" # This is the default wallet name within VegaServiceNull and CANNOT be changed
# Calling get_keypairs will internally call _load_tokens for the given wallet
keypairs = vega.wallet.get_keypairs(DEFAULT_WALLET_NAME)
wallet_api_token = vega.wallet.login_tokens[DEFAULT_WALLET_NAME]
# Set token to localStorage so eager connect hook picks it up and immediately connects
wallet_config = json.dumps(
{
"token": f"VWT {wallet_api_token}",
"connector": "jsonRpc",
"url": f"http://localhost:{vega.wallet_port}",
}
)
storage_javascript = [
# Store wallet config so eager connection is initiated
f"localStorage.setItem('vega_wallet_config', '{wallet_config}');",
# Ensure wallet ris dialog doesnt show, otherwise eager connect wont work
"localStorage.setItem('vega_wallet_risk_accepted', 'true');",
# Ensure initial risk dialog doesnt show
"localStorage.setItem('vega_risk_accepted', 'true');",
]
script = "".join(storage_javascript)
page.add_init_script(script)
return {
"wallet": DEFAULT_WALLET_NAME,
"wallet_api_token": wallet_api_token,
"public_key": keypairs["Key 1"],
}
@pytest.fixture(scope="function")
def auth(vega: VegaServiceNull, page: Page):
return auth_setup(vega, page)
# Set 'risk accepted' flag, so that the risk dialog doesn't show up
def risk_accepted_setup(page: Page):
onboarding_config = json.dumps({"state": {"dismissed": True}, "version": 0})
storage_javascript = [
"localStorage.setItem('vega_risk_accepted', 'true');",
f"localStorage.setItem('vega_onboarding', '{onboarding_config}');",
"localStorage.setItem('vega_telemetry_approval', 'false');",
"localStorage.setItem('vega_telemetry_viewed', 'true');",
]
script = "".join(storage_javascript)
page.add_init_script(script)
@pytest.fixture(scope="function")
def risk_accepted(page: Page):
risk_accepted_setup(page)
@pytest.fixture(scope="function")
def simple_market(vega, request):
kwargs = {}
if hasattr(request, "param"):
kwargs.update(request.param)
return setup_simple_market(vega, **kwargs)
@pytest.fixture(scope="function")
def opening_auction_market(vega):
return setup_opening_auction_market(vega)
@pytest.fixture(scope="function")
def continuous_market(vega):
return setup_continuous_market(vega)
@pytest.fixture(scope="function")
def proposed_market(vega):
return setup_simple_market(vega, approve_proposal=False)

View File

@ -0,0 +1,156 @@
from collections import namedtuple
from vega_sim.service import VegaService
from actions.vega import submit_multiple_orders, submit_order, submit_liquidity
import logging
logger = logging.getLogger()
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
mint_amount: float = 10e5
market_name = "BTC:DAI_2023"
def setup_simple_market(
vega: VegaService,
approve_proposal=True,
custom_market_name=market_name,
custom_asset_name="tDAI",
custom_asset_symbol="tDAI",
):
for wallet in wallets:
vega.create_key(wallet.name)
vega.mint(
MM_WALLET.name,
asset="VOTE",
amount=mint_amount,
)
vega.update_network_parameter(
MM_WALLET.name, parameter="market.fee.factors.makerFee", new_value="0.1"
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.create_asset(
MM_WALLET.name,
name=custom_asset_name,
symbol=custom_asset_symbol,
decimals=5,
max_faucet_amount=1e10,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
tdai_id = vega.find_asset_id(symbol=custom_asset_symbol)
logger.info(f"Created asset: {custom_asset_symbol}")
vega.mint(
"Key 1",
asset=tdai_id,
amount=mint_amount,
)
vega.mint(
MM_WALLET.name,
asset=tdai_id,
amount=mint_amount,
)
vega.mint(
MM_WALLET2.name,
asset=tdai_id,
amount=mint_amount,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
market_id = vega.create_simple_market(
custom_market_name,
proposal_key=MM_WALLET.name,
settlement_asset_id=tdai_id,
termination_key=TERMINATE_WALLET.name,
market_decimals=5,
approve_proposal=approve_proposal,
forward_time_to_enactment=approve_proposal,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return market_id
def setup_simple_successor_market(
vega: VegaService, parent_market_id, tdai_id, market_name, approve_proposal=True
):
market_id = vega.create_simple_market(
market_name,
proposal_key=MM_WALLET.name,
settlement_asset_id=tdai_id,
termination_key=MM_WALLET2.name,
market_decimals=5,
approve_proposal=approve_proposal,
forward_time_to_enactment=approve_proposal,
parent_market_id=parent_market_id,
parent_market_insurance_pool_fraction=0.5,
)
submit_liquidity(vega, MM_WALLET.name, market_id)
submit_multiple_orders(
vega, MM_WALLET.name, market_id, "SIDE_SELL", [[1, 110], [1, 105]]
)
submit_multiple_orders(
vega, MM_WALLET2.name, market_id, "SIDE_BUY", [[1, 90], [1, 95]]
)
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return market_id
def setup_opening_auction_market(vega: VegaService, market_id: str = None, **kwargs):
if market_id is None or market_id not in vega.all_markets():
market_id = setup_simple_market(vega, **kwargs)
submit_liquidity(vega, MM_WALLET.name, market_id)
submit_multiple_orders(
vega, MM_WALLET.name, market_id, "SIDE_SELL", [[1, 110], [1, 105]]
)
submit_multiple_orders(
vega, MM_WALLET2.name, market_id, "SIDE_BUY", [[1, 90], [1, 95]]
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return market_id
def setup_continuous_market(vega: VegaService, market_id: str = None, **kwargs):
if market_id is None or market_id not in vega.all_markets():
market_id = setup_opening_auction_market(vega, **kwargs)
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return market_id

1345
apps/trading/e2e/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
[tool.poetry]
name = "trading market-sim e2e"
version = "0.1.0"
description = ""
authors = ["Matthew Russell <mattrussell36@gmail.com>"]
readme = "README.md"
packages = [{include = "trading market-sim e2e"}]
[tool.poetry.dependencies]
python = ">=3.9,<3.11"
psutil = "^5.9.5"
vega-sim = {git = "https://github.com/vegaprotocol/vega-market-sim.git"}
pytest-playwright = "^0.4.2"
docker = "^6.1.3"
pytest-xdist = "^3.3.1"
python-dotenv = "^1.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
log_cli = true
log_cli_format = "%(asctime)s - %(name)s - %(levelname)s: %(message)s"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
log_cli_level = "INFO"
log_file_format = "%(asctime)s - %(name)s - %(levelname)s: %(message)s"
log_file_date_format = "%Y-%m-%d %H:%M:%S"
log_file_level = "INFO"

View File

@ -0,0 +1,95 @@
import pytest
import re
from playwright.sync_api import expect, Page
label_value_tooltip_pairs = [
{
"label": "ID",
"value": "asset-id",
},
{
"label": "Type",
"value": "Builtin asset",
"valueToolTip": "A Vega builtin asset",
},
{
"label": "Name",
"value": "tDAI",
},
{
"label": "Symbol",
"value": "tDAI",
},
{
"label": "Decimals",
"value": "5",
"labelTooltip": "Number of decimal / precision handled by this asset",
},
{
"label": "Quantum",
"value": "0.00001",
"labelTooltip": "The minimum economically meaningful amount of the asset",
},
{
"label": "Status",
"value": "Enabled",
"labelTooltip": "The status of the asset in the Vega network",
"valueToolTip": "Asset can be used on the Vega network",
},
{
"label": "Max faucet amount",
"value": "10,000,000,000.00",
"labelTooltip": "Maximum amount that can be requested by a party through the built-in asset faucet at a time",
},
{
"label": "Infrastructure fee account balance",
"value": "0.00",
"labelTooltip": "The infrastructure fee account in this asset",
},
{
"label": "Global reward pool account balance",
"value": "0.00",
"labelTooltip": "The global rewards acquired in this asset",
},
]
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)
page.get_by_test_id("dialog-title").click()
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_asset_details(page: Page):
page.goto("/#/portfolio")
page.locator('[data-testid="tab-collateral"] >> text=tDAI').click()
for index, pair in enumerate(label_value_tooltip_pairs):
if index in [7, 8, 9]: # Skip indices 7, 8, and 9.
continue
label = pair.get("label", "")
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()
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}"
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)
if label_tooltip:
tooltip(page, index, "label", label_tooltip)
if value_tooltip:
tooltip(page, index, "value", value_tooltip)
page.get_by_test_id("dialog-close").click()
assert not page.query_selector("dialog-content")

View File

@ -0,0 +1,13 @@
import pytest
from playwright.sync_api import expect, Page
@pytest.mark.usefixtures("page", "continuous_market", "risk_accepted")
def test_see_market_depth_chart(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
# Click on the 'Depth' tab
page.get_by_test_id("Depth").click()
# Check if the 'Depth' tab and the depth chart are visible
# 6006-DEPC-001
expect(page.get_by_test_id("tab-depth")).to_be_visible()
expect(page.locator('[class^="depth-chart-module_canvas__"]').first).to_be_visible()

View File

@ -0,0 +1,142 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from datetime import datetime, timedelta
from conftest import init_vega
from fixtures.market import setup_continuous_market
from actions.utils import wait_for_toast_confirmation
order_size = "order-size"
order_price = "order-price"
place_order = "place-order"
order_side_sell = "order-side-SIDE_SELL"
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")
def test_limit_buy_order_GTT(continuous_market, vega: VegaService, page: Page):
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.get_by_test_id(tif).select_option("Good 'til Time (GTT)")
expires_at = datetime.now() + timedelta(days=1)
expires_at_input_value = expires_at.strftime("%Y-%m-%dT%H:%M:%S")
page.get_by_test_id("date-picker-field").fill(expires_at_input_value)
# 7002-SORD-011
expect(page.get_by_test_id("place-order").locator("span").first).to_have_text(
"Place limit order"
)
expect(page.get_by_test_id("place-order").locator("span").last).to_have_text(
"10 BTC @ 120.00 BTC"
)
page.get_by_test_id(place_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
# 7002-SORD-017
expect(page.get_by_role("row").nth(2)).to_contain_text(
"BTC:DAI_2023Futr10+10LimitFilled120.00GTT:"
)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_limit_buy_order(continuous_market, vega: VegaService, page: Page):
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.get_by_test_id(place_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
# 7002-SORD-017
expect(page.get_by_role("row").nth(2)).to_contain_text(
"BTC:DAI_2023Futr10+10LimitFilled120.00GTC"
)
@pytest.mark.usefixtures("page", "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")
page.get_by_test_id(order_price).fill("100")
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(tif).select_option("Good for Normal (GFN)")
# 7002-SORD-011
expect(page.get_by_test_id("place-order").locator("span").first).to_have_text(
"Place limit order"
)
expect(page.get_by_test_id("place-order").locator("span").last).to_have_text(
"10 BTC @ 100.00 BTC"
)
page.get_by_test_id(place_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
expect(page.get_by_role("row").nth(2)).to_contain_text(
"BTC:DAI_2023Futr10-10LimitFilled100.00GFN"
)
@pytest.mark.usefixtures("page", "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()
page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(order_side_sell).click()
# 7002-SORD-011
expect(page.get_by_test_id("place-order").locator("span").first).to_have_text(
"Place market order"
)
expect(page.get_by_test_id("place-order").locator("span").last).to_have_text(
"10 BTC @ market"
)
page.get_by_test_id(place_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
expect(page.get_by_role("row").nth(2)).to_contain_text(
"BTC:DAI_2023Futr10-10MarketFilled-IOC"
)
@pytest.mark.usefixtures("page", "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()
page.get_by_test_id(order_size).fill("10")
page.get_by_test_id(tif).select_option("Fill or Kill (FOK)")
page.get_by_test_id(place_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
# 7002-SORD-010
# 0003-WTXN-012
# 0003-WTXN-003
expect(page.get_by_role("row").nth(2)).to_contain_text(
"BTC:DAI_2023Futr10+10MarketFilled-FOK"
)

View File

@ -0,0 +1,35 @@
import pytest
from playwright.sync_api import Page, expect
from conftest import init_vega
from fixtures.market import setup_continuous_market
@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.skip("We currently can't approve wallet connection through Sim")
@pytest.mark.usefixtures("page", "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")
page.get_by_test_id("order-connect-wallet").click()
expect(page.locator('[role="dialog"]')).to_be_visible()
page.get_by_test_id("connector-jsonRpc").click()
expect(page.get_by_test_id("wallet-dialog-title")).to_be_visible()
# TODO: accept wallet connection and assert wallet is connected.
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")
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()
page.get_by_test_id("Order").click()
expect(page.get_by_test_id("deal-ticket-form")).not_to_be_visible()
page.reload()
expect(page.get_by_test_id("deal-ticket-form")).to_be_visible()

View File

@ -0,0 +1,96 @@
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from actions.utils import wait_for_toast_confirmation
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
notional = "deal-ticket-fee-notional"
fees = "deal-ticket-fee-fees"
margin_required = "deal-ticket-fee-margin-required"
item_value = "item-value"
market_trading_mode = "market-trading-mode"
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "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
page.goto(f"/#/markets/{market_id}")
# submit order from UI and verify fees and margin
expect(page.get_by_test_id(notional)).to_have_text("Notional- BTC")
expect(page.get_by_test_id(fees)).to_have_text("Fees- tDAI")
expect(page.get_by_test_id(margin_required)).to_have_text(
"Margin required0.00 tDAI"
)
page.get_by_test_id("order-size").type("200")
page.get_by_test_id("order-price").type("20")
expect(page.get_by_test_id(notional)).to_have_text("Notional4,000.00 BTC")
expect(page.get_by_test_id(fees)).to_have_text("Fees~402.00 tDAI")
expect(page.get_by_test_id(margin_required)).to_have_text(
"Margin required1,661.88832 tDAI"
)
page.get_by_test_id("place-order").click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
expect(page.get_by_test_id(margin_required)).to_have_text(
"Margin required1,661.88832 tDAI "
)
page.get_by_test_id("toast-close").click()
# submit order by sim function
order = submit_order(vega, "Key 1", market_id, "SIDE_BUY", 400, 38329483272398.838)
vega.forward("20s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_test_id(margin_required)).to_have_text(
"Margin required897,716,007,278,798.50 tDAI "
)
expect(page.get_by_test_id("deal-ticket-warning-margin")).to_contain_text(
"You may not have enough margin available to open this position."
)
# cancel order and verify that warning margin disappeared
vega.cancel_order("Key 1", market_id, order)
vega.forward("20s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
expect(page.get_by_test_id("deal-ticket-warning-auction")).to_contain_text(
"Any orders placed now will not trade until the auction ends"
)
# add order at the current price so that it is possible to change the status to price monitoring
submit_order(vega, "Key 1", market_id, "SIDE_SELL", 1, 110)
vega.forward("20s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
page.reload()
expect(page.get_by_test_id(margin_required)).to_have_text(
"Margin required1,700.53688 tDAI"
)
expect(
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
).to_have_text("Continuous")
# verify if we can submit order after reverted margin
page.get_by_test_id("place-order").click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
# skip temporary
# expect(page.get_by_test_id("toast-content")).to_contain_text(
# "Your transaction has been confirmed"
# )

View File

@ -0,0 +1,416 @@
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from datetime import datetime, timedelta
from conftest import init_vega
from fixtures.market import setup_continuous_market
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
stop_order_btn = "order-type-Stop"
stop_limit_order_btn = "order-type-StopLimit"
stop_market_order_btn = "order-type-StopMarket"
order_side_sell = "order-side-SIDE_SELL"
trigger_above = "triggerDirection-risesAbove"
trigger_below = "triggerDirection-fallsBelow"
trigger_price = "triggerPrice"
trigger_type_price = "triggerType-price"
trigger_type_trailing_percent_offset = "triggerType-trailingPercentOffset"
order_size = "order-size"
order_price = "order-price"
order_tif = "order-tif"
expire = "expire"
expiry_strategy = '[for="expiryStrategy"]'
expiry_strategy_submit = "expiryStrategy-submit"
expiry_strategy_cancel = "expiryStrategy-cancel"
date_picker_field = "date-picker-field"
submit_stop_order = "place-order"
stop_orders_tab = "Stop orders"
row_table = "row"
cancel = "cancel"
market_name_col = '[col-id="market.tradableInstrument.instrument.code"]'
trigger_col = '[col-id="trigger"]'
expiresAt_col = '[col-id="expiresAt"]'
size_col = '[col-id="submission.size"]'
submission_type = '[col-id="submission.type"]'
status_col = '[col-id="status"]'
price_col = '[col-id="submission.price"]'
timeInForce_col = '[col-id="submission.timeInForce"]'
updatedAt_col = '[col-id="updatedAt"]'
close_toast = "toast-close"
def wait_for_graphql_response(page, query_name, timeout=5000):
response_data = {}
def handle_response(route, request):
if "graphql" in request.url:
response = request.response()
if response is not None:
json_response = response.json()
if json_response and "data" in json_response:
data = json_response["data"]
if query_name in data:
response_data["data"] = data
route.continue_()
return
route.continue_()
# Register the route handler
page.route("**", handle_response)
# Wait for the response data to be populated
page.wait_for_timeout(timeout)
# Unregister the route handler
page.unroute("**", handle_response)
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)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_stop_order_form_error_validation(continuous_market, page: Page):
# 7002-SORD-032
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(submit_stop_order).click()
expect(page.get_by_test_id("stop-order-error-message-trigger-price")).to_have_text(
"You need provide a price"
)
expect(page.get_by_test_id("stop-order-error-message-size")).to_have_text(
"Size cannot be lower than 1"
)
page.get_by_test_id(order_size).fill("1")
page.get_by_test_id(order_price).fill("0.0000001")
expect(page.get_by_test_id("stop-order-error-message-price")).to_have_text(
"Price cannot be lower than 0.00001"
)
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "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()
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(trigger_price).fill("103")
page.get_by_test_id(order_size).fill("3")
page.get_by_test_id(submit_stop_order).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(1)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(trigger_col)).nth(1)).to_have_text(
"Mark > 103.00"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(1)).to_have_text("")
expect((page.get_by_role(row_table).locator(size_col)).nth(1)).to_have_text("+3")
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(1)).to_have_text(
"Rejected"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(1)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(1)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(1)
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_market_order_triggered(
continuous_market, vega: VegaService, page: Page
):
# 7002-SORD-071
# 7002-SORD-074
# 7002-SORD-075
# 7002-SORD-067
# 7002-SORD-068
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click()
# create a position because stop order is reduce only type
create_position(vega, continuous_market)
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(trigger_price).fill("103")
page.get_by_test_id(order_size).fill("1")
page.get_by_test_id(expire).click()
expires_at = datetime.now() + timedelta(days=1)
expires_at_input_value = expires_at.strftime("%Y-%m-%dT%H:%M:%S")
page.get_by_test_id("date-picker-field").fill(expires_at_input_value)
page.get_by_test_id(expiry_strategy_cancel).click()
page.get_by_test_id(submit_stop_order).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.wait_for_selector('[data-testid="toast-close"]', state="visible")
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(1)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(trigger_col)).nth(1)).to_have_text(
"Mark > 103.00"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(1)).to_contain_text(
"Cancels"
)
expect((page.get_by_role(row_table).locator(size_col)).nth(1)).to_have_text("-1")
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(1)).to_have_text(
"Triggered"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(1)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(1)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(1)
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
def test_submit_stop_limit_order_pending(
continuous_market, vega: VegaService, page: Page
):
# 7002-SORD-071
# 7002-SORD-074
# 7002-SORD-075
# 7002-SORD-069
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click()
# create a position because stop order is reduce only type
create_position(vega, continuous_market)
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(trigger_below).click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_price).fill("99")
page.get_by_test_id(order_size).fill("1")
page.get_by_test_id("order-tif").select_option("TIME_IN_FORCE_IOC")
page.get_by_test_id(expire).click()
expires_at = datetime.now() + timedelta(days=1)
expires_at_input_value = expires_at.strftime("%Y-%m-%dT%H:%M:%S")
page.get_by_test_id("date-picker-field").fill(expires_at_input_value)
page.get_by_test_id(submit_stop_order).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.wait_for_selector('[data-testid="toast-close"]', state="visible")
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(1)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(trigger_col)).nth(1)).to_have_text(
"Mark < 102.00"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(1)).to_contain_text(
"Submit"
)
expect((page.get_by_role(row_table).locator(size_col)).nth(1)).to_have_text("-1")
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Limit"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(1)).to_have_text(
"Pending"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(1)).to_have_text(
"99.00"
)
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(1)).to_have_text(
"IOC"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(1)
).not_to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("continuous_market", "auth", "risk_accepted")
def test_submit_stop_limit_order_cancel(
continuous_market, vega: VegaService, page: Page
):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click()
# create a position because stop order is reduce only type
create_position(vega, continuous_market)
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(trigger_below).click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_price).fill("99")
page.get_by_test_id(order_size).fill("1")
page.get_by_test_id(submit_stop_order).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).first.click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(cancel).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).first.click()
expect(
(page.get_by_role(row_table).locator('[col-id="status"]')).nth(1)
).to_have_text("Cancelled")
class TestStopOcoValidation:
@pytest.fixture(scope="class")
def vega(self, request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="class")
def continuous_market(self, vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_stop_market_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-052
# 7002-SORD-055
# 7002-SORD-056
# 7002-SORD-057
# 7002-SORD-058
# 7002-SORD-064
# 7002-SORD-065
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
expect(
page.get_by_test_id("sidebar-content").get_by_text("Trigger").first
).to_be_visible()
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_have_text(
"Rises above"
)
expect(page.locator('[for="triggerDirection-fallsBelow"]')).to_have_text(
"Falls below"
)
page.get_by_test_id(trigger_price).click()
expect(page.get_by_test_id(trigger_price)).to_be_empty
expect(page.locator('[for="triggerType-price"]')).to_have_text("Price")
expect(page.locator('[for="triggerType-trailingPercentOffset"]')).to_have_text(
"Trailing Percent Offset"
)
expect(page.locator('[for="order-size"]')).to_have_text("Size")
page.get_by_test_id(order_size).click()
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")
def test_stop_limit_order_form_validation(self, continuous_market, page: Page):
# 7002-SORD-020
# 7002-SORD-021
# 7002-SORD-022
# 7002-SORD-033
# 7002-SORD-034
# 7002-SORD-035
# 7002-SORD-036
# 7002-SORD-037
# 7002-SORD-038
# 7002-SORD-049
# 7002-SORD-050
# 7002-SORD-051
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
expect(
page.get_by_test_id("sidebar-content").get_by_text("Trigger").first
).to_be_visible()
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_have_text(
"Rises above"
)
expect(page.locator('[for="triggerDirection-risesAbove"]')).to_be_checked
expect(page.locator('[for="triggerDirection-fallsBelow"]')).to_have_text(
"Falls below"
)
page.get_by_test_id(trigger_price).click()
expect(page.get_by_test_id(trigger_price)).to_be_empty
expect(page.locator('[for="triggerType-price"]')).to_have_text("Price")
expect(page.locator('[for="triggerType-price"]')).to_be_checked
expect(page.locator('[for="triggerType-trailingPercentOffset"]')).to_have_text(
"Trailing Percent Offset"
)
expect(page.locator('[for="order-size"]').first).to_have_text("Size")
expect(page.locator('[for="order-price"]').last).to_have_text("Price")
page.get_by_test_id(order_size).click()
expect(page.get_by_test_id(order_size)).to_be_empty
page.get_by_test_id(order_price).click()
expect(page.get_by_test_id(order_price)).to_be_empty()
@pytest.mark.skip("core issue")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_maximum_number_of_active_stop_orders(
self, continuous_market, vega: VegaService, page: Page
):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id(stop_orders_tab).click()
# create a position because stop order is reduce only type
create_position(vega, continuous_market)
for i in range(4):
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.get_by_test_id(trigger_below).click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_price).fill("99")
page.get_by_test_id(order_size).fill("1")
page.get_by_test_id(submit_stop_order).click()
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
if page.get_by_test_id(close_toast).is_visible():
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
# 7002-SORD-011
expect(page.get_by_test_id("stop-order-warning-limit")).to_have_text(
"There is a limit of 4 active stop orders per market. Orders submitted above the limit will be immediately rejected."
)

View File

@ -0,0 +1,498 @@
from math import exp
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from conftest import init_vega, page
from fixtures.market import setup_continuous_market
from actions.utils import wait_for_toast_confirmation
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
stop_order_btn = "order-type-Stop"
stop_limit_order_btn = "order-type-StopLimit"
stop_market_order_btn = "order-type-StopMarket"
order_side_sell = "order-side-SIDE_SELL"
trigger_above = "triggerDirection-risesAbove"
trigger_below = "triggerDirection-fallsBelow"
trigger_price = "triggerPrice"
trigger_type_price = "triggerType-price"
trigger_type_trailing_percent_offset = "triggerType-trailingPercentOffset"
order_size = "order-size"
order_price = "order-price"
order_tif = "order-tif"
expire = "expire"
expiry_strategy = '[for="expiryStrategy"]'
expiry_strategy_submit = "expiryStrategy-submit"
expiry_strategy_cancel = "expiryStrategy-cancel"
date_picker_field = "date-picker-field"
submit_stop_order = "place-order"
stop_orders_tab = "Stop orders"
row_table = "row"
cancel = "cancel"
market_name_col = '[col-id="market.tradableInstrument.instrument.code"]'
trigger_col = '[col-id="trigger"]'
expiresAt_col = '[col-id="expiresAt"]'
size_col = '[col-id="submission.size"]'
submission_type = '[col-id="submission.type"]'
status_col = '[col-id="status"]'
price_col = '[col-id="submission.price"]'
timeInForce_col = '[col-id="submission.timeInForce"]'
updatedAt_col = '[col-id="updatedAt"]'
close_toast = "toast-close"
trigger_direction_fallsBelow_oco = "triggerDirection-fallsBelow-oco"
trigger_direction_fallsAbove_oco = "triggerDirection-fallsAbove-oco"
oco = "oco"
trigger_price_oco = "triggerPrice-oco"
order_size_oco = "order-size-oco"
order_limit_price_oco = "order-price-oco"
def wait_for_graphql_response(page, query_name, timeout=5000):
response_data = {}
def handle_response(route, request):
if "graphql" in request.url:
response = request.response()
if response is not None:
json_response = response.json()
if json_response and "data" in json_response:
data = json_response["data"]
if query_name in data:
response_data["data"] = data
route.continue_()
return
route.continue_()
# Register the route handler
page.route("**", handle_response)
# Wait for the response data to be populated
page.wait_for_timeout(timeout)
# Unregister the route handler
page.unroute("**", handle_response)
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)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_order_market_oco_rejected(
continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(trigger_price).fill("103")
page.get_by_test_id(order_size).fill("3")
# 7002-SORD-098
expect(
page.get_by_test_id("stop-order-warning-message-trigger-price")
).to_have_text("Stop order will be triggered immediately")
# 7002-SORD-082
page.get_by_test_id(oco).click()
# 7002-SORD-085
expect(page.get_by_test_id(trigger_direction_fallsBelow_oco)).to_be_checked
# 7002-SORD-086
page.get_by_test_id(trigger_price_oco).fill("102")
page.get_by_test_id(order_size_oco).fill("3")
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(1)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(1)).to_have_text("")
expect((page.get_by_role(row_table).locator(size_col)).nth(1)).to_have_text("+3")
# 7002-SORD-083
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(1)).to_have_text(
"RejectedOCO"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(1)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(1)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(1)
).not_to_be_empty()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(2)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(2)).to_have_text("")
expect((page.get_by_role(row_table).locator(size_col)).nth(2)).to_have_text("+3")
expect((page.get_by_role(row_table).locator(submission_type)).nth(2)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(2)).to_have_text(
"RejectedOCO"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(2)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(2)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(2)
).not_to_be_empty()
# 7002-SORD-084
trigger_price_list = (
page.locator(".ag-center-cols-container").locator(trigger_col).all_inner_texts()
)
trigger_value_list = ["Mark < 102.00", "Mark > 103.00"]
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_market_order_triggered(
continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
create_position(vega, market_id)
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(trigger_price).fill("103")
page.get_by_test_id(order_size).fill("3")
expect(
page.get_by_test_id("stop-order-warning-message-trigger-price")
).to_have_text("Stop order will be triggered immediately")
page.get_by_test_id(oco).click()
expect(page.get_by_test_id(trigger_direction_fallsBelow_oco)).to_be_checked
page.get_by_test_id(trigger_price_oco).fill("102")
page.get_by_test_id(order_size_oco).fill("3")
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(1)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(1)).to_have_text("")
expect((page.get_by_role(row_table).locator(size_col)).nth(1)).to_have_text("+3")
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(1)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(1)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(1)
).not_to_be_empty()
expect((page.get_by_role(row_table).locator(market_name_col)).nth(2)).to_have_text(
"BTC:DAI_2023Futr"
)
expect((page.get_by_role(row_table).locator(expiresAt_col)).nth(2)).to_have_text("")
expect((page.get_by_role(row_table).locator(size_col)).nth(2)).to_have_text("+3")
expect((page.get_by_role(row_table).locator(submission_type)).nth(2)).to_have_text(
"Market"
)
expect((page.get_by_role(row_table).locator(price_col)).nth(2)).to_have_text("-")
expect((page.get_by_role(row_table).locator(timeInForce_col)).nth(2)).to_have_text(
"FOK"
)
expect(
(page.get_by_role(row_table).locator(updatedAt_col)).nth(2)
).not_to_be_empty()
status = (
page.locator(".ag-center-cols-container").locator(status_col).all_inner_texts()
)
value = ["StoppedOCO", "TriggeredOCO"]
assert status.sort() == value.sort()
trigger_price_list = (
page.locator(".ag-center-cols-container").locator(trigger_col).all_inner_texts()
)
trigger_value_list = ["Mark < 102.00", "Mark > 103.00"]
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_market_order_pending(
continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
create_position(vega, market_id)
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.locator("label").filter(has_text="Falls below").click()
page.get_by_test_id(trigger_price).fill("99")
page.get_by_test_id(order_size).fill("3")
page.get_by_test_id(oco).click()
expect(page.get_by_test_id(trigger_direction_fallsAbove_oco)).to_be_checked
page.get_by_test_id(trigger_price_oco).fill("120")
page.get_by_test_id(order_size_oco).fill("2")
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(status_col)).nth(1)).to_have_text(
"PendingOCO"
)
expect((page.get_by_role(row_table).locator(status_col)).nth(2)).to_have_text(
"PendingOCO"
)
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_limit_order_pending(
continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
create_position(vega, market_id)
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.locator("label").filter(has_text="Falls below").click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_size).fill("3")
page.get_by_test_id(order_price).fill("103")
page.get_by_test_id(oco).click()
# 7002-SORD-090
expect(page.get_by_test_id(trigger_direction_fallsAbove_oco)).to_be_checked
page.get_by_test_id(trigger_price_oco).fill("120")
page.get_by_test_id(order_size_oco).fill("2")
# 7002-SORD-089
page.get_by_test_id(order_limit_price_oco).fill("99")
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_role(row_table).locator(market_name_col).nth(1).is_visible()
expect((page.get_by_role(row_table).locator(submission_type)).nth(1)).to_have_text(
"Limit"
)
expect((page.get_by_role(row_table).locator(submission_type)).nth(2)).to_have_text(
"Limit"
)
price = (
page.locator(".ag-center-cols-container").locator(price_col).all_inner_texts()
)
prices = ["103.00", "99.00"]
assert price.sort() == prices.sort()
# 7002-SORD-091
trigger_price_list = (
page.locator(".ag-center-cols-container").locator(trigger_col).all_inner_texts()
)
trigger_value_list = ["Limit < 102.00", "Limit > 103.00"]
assert trigger_price_list.sort() == trigger_value_list.sort()
@pytest.mark.usefixtures("page", "vega", "continuous_market", "auth", "risk_accepted")
def test_submit_stop_oco_limit_order_cancel(
continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
create_position(vega, market_id)
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.locator("label").filter(has_text="Falls below").click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_size).fill("3")
page.get_by_test_id(order_price).fill("103")
page.get_by_test_id(oco).click()
# 7002-SORD-092
expect(page.get_by_test_id(trigger_direction_fallsAbove_oco)).to_be_checked
# 7002-SORD-094
page.get_by_test_id(trigger_price_oco).fill("120")
page.get_by_test_id(order_size_oco).fill("2")
# 7002-SORD-093
page.get_by_test_id(order_limit_price_oco).fill("99")
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(cancel).first.click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id(close_toast).first.click()
expect(
page.locator(".ag-center-cols-container").locator('[col-id="status"]').first
).to_have_text("CancelledOCO")
expect(
page.locator(".ag-center-cols-container").locator('[col-id="status"]').last
).to_have_text("CancelledOCO")
class TestStopOcoValidation:
@pytest.fixture(scope="class")
def vega(self, request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="class")
def continuous_market(self, vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_stop_market_order_oco_form_validation(self, continuous_market, page: Page):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_market_order_btn).click()
page.get_by_test_id(oco).click()
expect(
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
).to_be_visible()
# 7002-SORD-084
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
"Rises above"
)
# 7002-SORD-085
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
"Falls below"
)
# 7002-SORD-087
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
expect(page.locator('[for="triggerType-price"]')).to_be_checked
# 7002-SORD-088
expect(
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
).to_have_text("Trailing Percent Offset")
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_stop_limit_order_oco_form_validation(self, continuous_market, page: Page):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_market_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(oco).click()
expect(
page.get_by_test_id("sidebar-content").get_by_text("Trigger").last
).to_be_visible()
# 7002-SORD-099
expect(page.locator('[for="triggerDirection-risesAbove-oco"]')).to_have_text(
"Rises above"
)
# 7002-SORD-091
expect(page.locator('[for="triggerDirection-fallsBelow-oco"]')).to_have_text(
"Falls below"
)
# 7002-SORD-095
expect(page.locator('[for="triggerType-price-oco"]')).to_have_text("Price")
expect(page.locator('[for="triggerType-price"]')).to_be_checked
# 7002-SORD-095
expect(
page.locator('[for="triggerType-trailingPercentOffset-oco"]')
).to_have_text("Trailing Percent Offset")
expect(page.locator('[for="order-size-oco"]')).to_have_text("Size")
expect(page.locator('[for="order-price-oco"]')).to_have_text("Price")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_maximum_number_of_active_stop_orders_oco(
self, continuous_market, vega: VegaService, page: Page
):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
page.get_by_test_id(stop_orders_tab).click()
create_position(vega, market_id)
wait_for_graphql_response(page, "stopOrders")
page.get_by_test_id(stop_order_btn).click()
page.get_by_test_id(stop_limit_order_btn).is_visible()
page.get_by_test_id(stop_limit_order_btn).click()
page.get_by_test_id(order_side_sell).click()
page.locator("label").filter(has_text="Falls below").click()
page.get_by_test_id(trigger_price).fill("102")
page.get_by_test_id(order_size).fill("3")
page.get_by_test_id(order_price).fill("103")
page.get_by_test_id(oco).click()
page.get_by_test_id(trigger_price_oco).fill("120")
page.get_by_test_id(order_size_oco).fill("2")
page.get_by_test_id(order_limit_price_oco).fill("99")
for i in range(2):
page.get_by_test_id(submit_stop_order).click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
if page.get_by_test_id(close_toast).is_visible():
page.get_by_test_id(close_toast).click()
wait_for_graphql_response(page, "stopOrders")
# 7002-SORD-011
expect(page.get_by_test_id("stop-order-warning-limit")).to_have_text(
"There is a limit of 4 active stop orders per market. Orders submitted above the limit will be immediately rejected."
)

View File

@ -0,0 +1,51 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.utils import wait_for_toast_confirmation
from conftest import init_vega
from fixtures.market import setup_continuous_market
order_size = "order-size"
order_price = "order-price"
place_order = "place-order"
deal_ticket_warning_margin = "deal-ticket-warning-margin"
deal_ticket_deposit_dialog_button = "deal-ticket-deposit-dialog-button"
@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")
def test_should_display_info_and_button_for_deposit(continuous_market, vega: VegaService, 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")
# 7002-SORD-060
expect(page.get_by_test_id(deal_ticket_warning_margin)).to_have_text("You may not have enough margin available to open this position.")
page.get_by_test_id(deal_ticket_warning_margin).hover()
expect(page.get_by_test_id("tooltip-content").nth(0)).to_have_text("1,661,896.6317 tDAI is currently required.You have only 1,000,000.00.Deposit tDAI")
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")
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")
page.get_by_test_id("manage-vega-wallet").click()
page.locator('[role="menuitemradio"]').nth(4).click()
page.reload()
page.get_by_test_id(order_size).fill("200")
page.get_by_test_id(order_price).fill("20")
# 7002-SORD-060
expect(page.get_by_test_id(place_order)).to_be_enabled()
# 7002-SORD-003
expect(page.get_by_test_id("deal-ticket-error-message-zero-balance")).to_have_text("You need tDAI in your wallet to trade in this market. Make a deposit")
expect(page.get_by_test_id(deal_ticket_deposit_dialog_button)).to_be_visible()

View File

@ -0,0 +1,205 @@
import pytest
from playwright.sync_api import expect, Page
import json
from vega_sim.service import VegaService
from fixtures.market import setup_simple_market
from conftest import init_vega
from collections import namedtuple
from actions.vega import submit_order
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
expect(page.get_by_test_id("order-connect-wallet")).to_be_visible
expect(page.get_by_test_id("order-connect-wallet")).to_be_enabled
# 0007-FUGS-006
# 0007-FUGS-002
expect(page.locator(".list-none")).to_contain_text(
"1.Connect2.Deposit funds3.Open a position"
)
DEFAULT_WALLET_NAME = "MarketSim" # This is the default wallet name within VegaServiceNull and CANNOT be changed
# Calling get_keypairs will internally call _load_tokens for the given wallet
keypairs = vega.wallet.get_keypairs(DEFAULT_WALLET_NAME)
wallet_api_token = vega.wallet.login_tokens[DEFAULT_WALLET_NAME]
# Set token to localStorage so eager connect hook picks it up and immediately connects
wallet_config = json.dumps(
{
"token": f"VWT {wallet_api_token}",
"connector": "jsonRpc",
"url": f"http://localhost:{vega.wallet_port}",
}
)
storage_javascript = [
# Store wallet config so eager connection is initiated
f"localStorage.setItem('vega_wallet_config', '{wallet_config}');",
# Ensure wallet ris dialog doesnt show, otherwise eager connect wont work
"localStorage.setItem('vega_wallet_risk_accepted', 'true');",
# Ensure initial risk dialog doesnt show
"localStorage.setItem('vega_risk_accepted', 'true');",
]
script = "".join(storage_javascript)
page.add_init_script(script)
page.reload()
# Assert step 1 complete
expect(page.get_by_test_id("icon-tick")).to_have_count(1)
env = json.dumps(
{
"VEGA_URL": f"http://localhost:{vega.data_node_rest_port}/graphql",
"VEGA_WALLET_URL": f"http://localhost:{vega.wallet_port}",
}
)
window_env = f"window._env_ = Object.assign({{}}, window._env_, {env})"
page.add_init_script(script=window_env)
page.reload()
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
mint_amount: float = 10e5
for wallet in wallets:
vega.create_key(wallet.name)
vega.mint(
MM_WALLET.name,
asset="VOTE",
amount=mint_amount,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.create_asset(
MM_WALLET.name,
name="tDAI",
symbol="tDAI",
decimals=5,
max_faucet_amount=1e10,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
tdai_id = vega.find_asset_id(symbol="tDAI")
logger.info(f"tDAI: {tdai_id}")
vega.mint(
"Key 1",
asset=tdai_id,
amount=10,
)
vega.wait_fn(1)
vega.wait_for_total_catchup()
# Assert step 2 complete
expect(page.get_by_test_id("icon-tick")).to_have_count(2)
market_id = vega.create_simple_market(
"tDAI",
proposal_key=MM_WALLET.name,
settlement_asset_id=tdai_id,
termination_key=TERMINATE_WALLET.name,
market_decimals=5,
approve_proposal=True,
forward_time_to_enactment=True,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("get-started-button").click()
# Assert dialog isn't visible
expect(page.get_by_test_id("welcome-dialog")).not_to_be_visible()
@pytest.mark.usefixtures("page", "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")
page.wait_for_selector('[data-testid="connect-vega-wallet"]', state="attached")
expect(get_started_locator).to_be_enabled
expect(get_started_locator).to_be_visible
# 0007-FUGS-015
expect(get_started_locator).to_have_text("Get started")
get_started_locator.click()
# 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}")
locator = page.get_by_test_id("connect-vega-wallet")
page.wait_for_selector('[data-testid="connect-vega-wallet"]', state="attached")
expect(locator).to_be_enabled
expect(locator).to_be_visible
expect(locator).to_have_text("Connect")
@pytest.mark.usefixtures("page", "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")
def test_browser_wallet_installed_deal_ticket(simple_market, page: Page):
page.add_init_script("window.vega = {}")
page.goto(f"/#/markets/{simple_market}")
# 0007-FUGS-013
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
expect(page).to_have_url(
f"http://localhost:{vega.console_port}/#/markets/{continuous_market}"
)
page.get_by_test_id("icon-cross").click()
# 0007-FUGS-018
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)
page.get_by_test_id("browse-markets-button").click()
# 0007-FUGS-005
expect(page).to_have_url(f"http://localhost:{vega.console_port}/#/markets/{simple_market}")

View File

@ -0,0 +1,182 @@
import pytest
from collections import namedtuple
from playwright.sync_api import expect, Page
from vega_sim.service import VegaService
from actions.vega import submit_order
from conftest import init_vega
from fixtures.market import setup_continuous_market
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
def hover_and_assert_tooltip(page: Page, element_text):
element = page.get_by_text(element_text)
element.hover()
expect(page.get_by_role("tooltip")).to_be_visible()
class TestIcebergOrdersValidations:
@pytest.fixture(scope="class")
def vega(self, request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="class")
def continuous_market(self, vega):
return setup_continuous_market(vega)
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_iceberg_submit(self, continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("iceberg").click()
page.get_by_test_id("order-peak-size").type("2")
page.get_by_test_id("order-minimum-size").type("1")
page.get_by_test_id("order-size").type("3")
page.get_by_test_id("order-price").type("107")
page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("toast-content")).to_have_text(
"Awaiting confirmationPlease wait for your transaction to be confirmedView in block explorer"
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_test_id("toast-content")).to_have_text(
"Order filledYour transaction has been confirmed View in block explorerSubmit order - filledBTC:DAI_2023+3 @ 107.00 tDAI"
)
page.get_by_test_id("All").click()
expect(
(page.get_by_role("row").locator('[col-id="type"]')).nth(1)
).to_have_text("Limit (Iceberg)")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_iceberg_tooltips(self, continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("iceberg").hover()
expect(page.get_by_role("tooltip")).to_be_visible()
page.get_by_test_id("iceberg").click()
hover_and_assert_tooltip(page, "Peak size")
hover_and_assert_tooltip(page, "Minimum size")
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_iceberg_validations(self, continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("iceberg").click()
page.get_by_test_id("place-order").click()
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
"You need to provide a peak size"
)
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
"You need to provide a minimum visible size"
)
page.get_by_test_id("order-peak-size").clear()
page.get_by_test_id("order-peak-size").type("1")
page.get_by_test_id("order-minimum-size").clear()
page.get_by_test_id("order-minimum-size").type("2")
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-peak-error-message")).to_have_text(
"Peak size cannot be greater than the size (0)"
)
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
"Minimum visible size cannot be greater than the peak size (1)"
)
page.get_by_test_id("order-minimum-size").clear()
page.get_by_test_id("order-minimum-size").type("0.1")
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_be_visible()
expect(page.get_by_test_id("deal-ticket-minimum-error-message")).to_have_text(
"Minimum visible size cannot be lower than 1"
)
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
def test_iceberg_open_order(continuous_market, vega: VegaService, page: Page):
page.goto(f"/#/markets/{continuous_market}")
submit_order(vega, "Key 1", continuous_market, "SIDE_SELL", 102, 101, 2, 1)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.wait_for_selector(".ag-center-cols-container .ag-row")
expect(
page.locator(
".ag-center-cols-container .ag-row [col-id='openVolume'] [data-testid='stack-cell-primary']"
)
).to_have_text("-98")
page.get_by_test_id("Open").click()
page.wait_for_selector(".ag-center-cols-container .ag-row")
expect(
page.locator(".ag-center-cols-container .ag-row [col-id='remaining']")
).to_have_text("99")
expect(
page.locator(".ag-center-cols-container .ag-row [col-id='size']")
).to_have_text("-102")
expect(
page.locator(".ag-center-cols-container .ag-row [col-id='type'] ")
).to_have_text("Limit (Iceberg)")
expect(
page.locator(".ag-center-cols-container .ag-row [col-id='status']")
).to_have_text("Active")
expect(page.get_by_test_id("price-10100000")).to_be_visible
expect(page.get_by_test_id("ask-vol-10100000")).to_have_text("3")
page.get_by_test_id("Trades").click()
expect(page.locator('[id^="cell-price-"]').first).to_have_text("101.50")
expect(page.locator('[id^="cell-size-"]').first).to_have_text("99")
submit_order(vega, MM_WALLET2.name, continuous_market, "SIDE_BUY", 103, 101)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(
page.locator(
'[data-testid="tab-open-orders"] .ag-center-cols-container .ag-row'
)
).not_to_be_visible
page.get_by_test_id("Closed").click()
expect(
page.locator(".ag-center-cols-container .ag-row [col-id='remaining']").first
).to_have_text("102")
expect(
page.locator(
"[data-testid=\"tab-closed-orders\"] .ag-center-cols-container .ag-row [col-id='size']"
).first
).to_have_text("-102")
expect(
page.locator(
"[data-testid=\"tab-closed-orders\"] .ag-center-cols-container .ag-row [col-id='type']"
).first
).to_have_text("Limit (Iceberg)")
expect(
page.locator(
"[data-testid=\"tab-closed-orders\"] .ag-center-cols-container .ag-row [col-id='status']"
).first
).to_have_text("Filled")
expect(page.locator('[id^="cell-price-"]').nth(2)).to_have_text("101.00")
expect(page.locator('[id^="cell-size-"]').nth(2)).to_have_text("3")
def verify_order_label(page: Page, test_id: str, expected_text: str):
element = page.get_by_test_id(test_id)
expect(element).to_be_visible()
expect(element).to_have_text(expected_text)
def verify_order_value(page: Page, test_id: str, expected_text: str):
element = page.get_by_test_id(test_id)
expect(element).to_be_visible()
expect(element).to_have_text(expected_text)

View File

@ -0,0 +1,52 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from conftest import init_vega
from fixtures.market import setup_continuous_market
from actions.utils import next_epoch
@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")
def test_liquidity_provision_amendment(continuous_market, vega: VegaService, page: Page):
# TODO Refactor asserting the grid
page.goto(f"/#/liquidity/{continuous_market}")
page.get_by_test_id("manage-vega-wallet").click()
#TODO Rename "mm" to "marketMaker" so that we don't have to specify where to click when switching wallets
# Currently the default click will click the middle of the element which will click the copy wallet key button
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
page.reload()
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Active"
)
vega.submit_simple_liquidity(
key_name="mm",
market_id=continuous_market,
commitment_amount=100,
fee=0.001,
is_amendment=True,
)
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
expect(row).to_contain_text(
"Updating next epoch"
)
next_epoch(vega=vega)
page.reload()
row = page.get_by_test_id("tab-myLP").locator(".ag-center-cols-container .ag-row").first
expect(row).to_contain_text(
"Active"
)

View File

@ -0,0 +1,135 @@
import pytest
import re
import vega_sim.api.governance as governance
from vega_sim.service import VegaService
from playwright.sync_api import Page, expect
from fixtures.market import setup_continuous_market
from conftest import init_vega
@pytest.fixture(scope="class")
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)
vega.submit_termination_and_settlement_data(
settlement_key="FJMKnwfZdd48C8NqvYrG",
settlement_price=110,
market_id=market_id,
)
vega.forward("10s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
class TestSettledMarket:
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_settled_header(self, page: Page, create_settled_market):
page.goto(f"/#/markets/all")
page.get_by_test_id("Closed markets").click()
headers = [
"Market",
"Status",
"Settlement date",
"Best bid",
"Best offer",
"Mark price",
"Settlement price",
"Settlement asset",
"",
]
page.wait_for_selector('[data-testid="tab-closed-markets"]', state="visible")
page_headers = (
page.get_by_test_id("tab-closed-markets")
.locator(".ag-header-cell-text")
.all()
)
for i, header in enumerate(headers):
expect(page_headers[i]).to_have_text(header)
@pytest.mark.usefixtures(
"risk_accepted",
"auth",
)
def test_settled_rows(self, page: Page, create_settled_market):
page.goto(f"/#/markets/all")
page.get_by_test_id("Closed markets").click()
row_selector = page.locator(
'[data-testid="tab-closed-markets"] .ag-center-cols-container .ag-row'
).first
# 6001-MARK-001
expect(row_selector.locator('[col-id="code"]')).to_have_text("BTC:DAI_2023Futr")
# 6001-MARK-003
expect(row_selector.locator('[col-id="state"]')).to_have_text("Settled")
# 6001-MARK-004
# 6001-MARK-005
# 6001-MARK-009
# 6001-MARK-008
# 6001-MARK-010
pattern = r"(\d+)\s+months\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}"
expected_pattern = re.compile(r"https://.*?/oracles/[a-f0-9]{64}")
actual_href = row_selector.locator(
'[col-id="settlementDate"] [data-testid="link"]'
).get_attribute("href")
assert expected_pattern.match(
actual_href
), f"Expected href to match {expected_pattern.pattern}, but got {actual_href}"
# 6001-MARK-011
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
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
# expect(row_selector.locator('[col-id="settlementDataOracleId"]')).to_have_text(
# "110.00"
# )
expected_pattern = re.compile(r"https://.*?/oracles/[a-f0-9]{64}")
actual_href = row_selector.locator(
'[col-id="settlementDataOracleId"] [data-testid="link"]'
).get_attribute("href")
assert expected_pattern.match(
actual_href
), f"Expected href to match {expected_pattern.pattern}, but got {actual_href}"
# 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}"
@pytest.mark.usefixtures("risk_accepted", "auth")
def test_terminated_market_no_settlement_date(page: Page, vega: VegaService):
setup_continuous_market(vega)
print("I have started test_terminated_market_no_settlement_date")
governance.submit_oracle_data(
wallet=vega.wallet,
payload={"trading.terminated": "true"},
key_name="FJMKnwfZdd48C8NqvYrG",
)
vega.forward("60s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
page.goto(f"/#/markets/all")
page.get_by_test_id("Closed markets").click()
row_selector = page.locator(
'[data-testid="tab-closed-markets"] .ag-center-cols-container .ag-row'
).first
expect(row_selector.locator('[col-id="state"]')).to_have_text("Trading Terminated")
expect(row_selector.locator('[col-id="settlementDate"]')).to_have_text("Unknown")
# TODO Create test for terminated market with settlement date in future
# TODO Create test for terminated market with settlement date in past

View File

@ -0,0 +1,208 @@
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService, PeggedOrder
from actions.vega import submit_order
import logging
logger = logging.getLogger()
# Wallet Configurations
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
table_row_selector = (
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row'
)
trading_mode_col = '[col-id="tradingMode"]'
state_col = '[col-id="state"]'
item_value = "item-value"
price_monitoring_bounds_row = "key-value-table-row"
market_trading_mode = "market-trading-mode"
market_state = "market-state"
liquidity_supplied = "liquidity-supplied"
item_value = "item-value"
price_monitoring_bounds_row = "key-value-table-row"
market_trading_mode = "market-trading-mode"
market_state = "market-state"
liquidity_supplied = "liquidity-supplied"
initial_commitment: float = 100
initial_price: float = 1
initial_volume: float = 1
initial_spread: float = 0.1
market_name = "BTC:DAI_2023"
@pytest.mark.usefixtures("vega", "page", "simple_market", "risk_accepted")
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(
"Opening auction"
)
expect(page.locator(table_row_selector).locator('[col-id="state"]')).to_have_text(
"Pending"
)
result = page.get_by_text(market_name)
result.first.click()
page.get_by_test_id(market_trading_mode).get_by_text("Opening auction").hover()
expect(page.get_by_test_id("opening-auction-sub-status").first).to_have_text(
"Opening auction: Not enough liquidity to open"
)
logger.info(page.get_by_test_id("opening-auction-sub-status").inner_text)
vega.submit_liquidity(
key_name=MM_WALLET.name,
market_id=simple_market,
commitment_amount=initial_commitment,
fee=0.002,
is_amendment=False,
)
vega.submit_order(
market_id=simple_market,
trading_key=MM_WALLET.name,
side="SIDE_BUY",
order_type="TYPE_LIMIT",
price=initial_price - 0.0005,
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
vega.submit_order(
market_id=simple_market,
trading_key=MM_WALLET.name,
side="SIDE_SELL",
order_type="TYPE_LIMIT",
price=initial_price + 0.0005,
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("0.00 (0.00%)")
# add orders to provide liquidity
submit_order(
vega, MM_WALLET.name, simple_market, "SIDE_BUY", initial_volume, initial_price
)
submit_order(
vega, MM_WALLET.name, simple_market, "SIDE_SELL", initial_volume, initial_price
)
submit_order(
vega,
MM_WALLET.name,
simple_market,
"SIDE_BUY",
initial_volume,
initial_price + initial_spread / 2,
)
submit_order(
vega,
MM_WALLET.name,
simple_market,
"SIDE_SELL",
initial_volume,
initial_price + initial_spread / 2,
)
submit_order(
vega, MM_WALLET2.name, simple_market, "SIDE_SELL", initial_volume, initial_price
)
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("100.00 (>100%)")
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("50.00 (>100%)")
page.goto(f"/#/markets/all")
# temporary skip
# expect(page.locator(table_row_selector).locator(trading_mode_col)).to_have_text(
# "Continuous"
# )
# commented out because we have an issue #4233
# expect(page.locator(row_selector).locator(state_col)
# ).to_have_text("Pending")
page.goto(f"/#/markets/all")
result = page.get_by_text(market_name)
result.first.click()
page.get_by_test_id("Info").click()
page.get_by_test_id("accordion-title").get_by_text(
"Price monitoring bounds 1"
).click()
expect(
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
"1.32217 BTC"
)
).to_be_visible()
expect(
page.get_by_test_id(price_monitoring_bounds_row).last.get_by_text("0.79245 BTC")
).to_be_visible()
# add orders that change the price so that it goes beyond the limits of price monitoring
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 110)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 90)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 105)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 95)
# add order at the current price so that it is possible to change the status to price monitoring
to_cancel = submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 1, 105)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(
page.get_by_test_id(price_monitoring_bounds_row).first.get_by_text(
"135.44204 BTC"
)
).to_be_visible()
expect(
page.get_by_test_id(price_monitoring_bounds_row).last.get_by_text(
"81.17758 BTC"
)
).to_be_visible()
expect(
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
).to_have_text("Monitoring auction - price")
expect(page.get_by_test_id(market_state).get_by_test_id(item_value)).to_have_text(
"Suspended"
)
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("50.00 (8.78%)")
# cancel order to increase liquidity
vega.cancel_order(MM_WALLET2.name, simple_market, to_cancel)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_text(market_name).first).to_be_attached()
expect(
page.get_by_test_id(market_trading_mode).get_by_test_id(item_value)
).to_have_text("Continuous")
expect(page.get_by_test_id(market_state).get_by_test_id(item_value)).to_have_text(
"Active"
)
# commented out because we have an issue #4233
# expect(page.get_by_text("Opening auction")).to_be_hidden()
expect(
page.get_by_test_id(liquidity_supplied).get_by_test_id(item_value)
).to_have_text("50.00 (>100%)")

View File

@ -0,0 +1,294 @@
import re
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"
@pytest.fixture(scope="module")
def vega():
with init_vega() as 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):
with init_page(vega, browser, request) as page:
setup_continuous_market(vega)
risk_accepted_setup(page)
page.goto("/")
page.get_by_test_id("Info").click()
yield page
@pytest.fixture(autouse=True)
def after_each(page: Page):
yield
opened_element = page.locator('h3[data-state="open"]')
if opened_element.all() and opened_element.get_by_role("button").is_visible():
opened_element.get_by_role("button").click()
def validate_info_section(page: Page, fields: [[str, str]]):
for rowNumber, field in enumerate(fields):
name, value = field
expect(
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dt")
).to_contain_text(name)
expect(
page.get_by_test_id("key-value-table-row").nth(rowNumber).locator("dd")
).to_contain_text(value)
def test_market_info_current_fees(page: Page):
# 6002-MDET-101
page.get_by_test_id(market_title_test_id).get_by_text("Current fees").click()
fields = [
["Maker Fee", "10%"],
["Infrastructure Fee", "0.05%"],
["Liquidity Fee", "0%"],
["Total Fees", "10.05%"],
]
validate_info_section(page, fields)
def test_market_info_market_price(page: Page):
# 6002-MDET-102
page.get_by_test_id(market_title_test_id).get_by_text("Market price").click()
fields = [
["Mark Price", "107.50"],
["Best Bid Price", "101.50"],
["Best Offer Price", "103.50"],
["Quote Unit", "BTC"],
]
validate_info_section(page, fields)
def test_market_info_market_volume(page: Page):
# 6002-MDET-103
page.get_by_test_id(market_title_test_id).get_by_text("Market volume").click()
fields = [
["24 Hour Volume", "-"],
["Open Interest", "1"],
["Best Bid Volume", "99"],
["Best Offer Volume", "99"],
["Best Static Bid Volume", "1"],
["Best Static Offer Volume", "1"],
]
validate_info_section(page, fields)
def test_market_info_insurance_pool(page: Page):
# 6002-MDET-104
page.get_by_test_id(market_title_test_id).get_by_text("Insurance pool").click()
fields = [["Balance", "0.00 tDAI"]]
validate_info_section(page, fields)
def test_market_info_key_details(page: Page, vega: VegaService):
# 6002-MDET-201
page.get_by_test_id(market_title_test_id).get_by_text("Key details").click()
market_id = vega.find_market_id("BTC:DAI_2023")
short_market_id = market_id[:6] + "" + market_id[-4:]
fields = [
["Market ID", short_market_id],
["Name", "BTC:DAI_2023"],
["Parent Market ID", "-"],
["Insurance Pool Fraction", "-"],
["Status", "Active"],
["Trading Mode", "Continuous"],
["Market Decimal Places", "5"],
["Position Decimal Places", "0"],
["Settlement Asset Decimal Places", "5"],
]
validate_info_section(page, fields)
def test_market_info_instrument(page: Page):
# 6002-MDET-202
page.get_by_test_id(market_title_test_id).get_by_text("Instrument").click()
fields = [
["Market Name", "BTC:DAI_2023"],
["Code", "BTC:DAI_2023"],
["Product Type", "Future"],
["Quote Name", "BTC"],
]
validate_info_section(page, fields)
# @pytest.mark.skip("oracle test to be fixed")
def test_market_info_oracle(page: Page, vega: VegaService):
# 6002-MDET-203
page.get_by_test_id(market_title_test_id).get_by_text("Oracle").click()
expect(
page.locator('[data-state="open"]').get_by_test_id("accordion-content")
).to_contain_text("No oracle proof for settlement data")
expect(page.get_by_test_id("oracle-spec-links")).to_have_text(
"View settlement data specification"
)
# expect(page.get_by_test_id("oracle-spec-links")).to_have_attribute(
# "href", re.compile(rf'(\/oracles\/{vega.find_market_id("BTC:DAI_2023")})')
# )
def test_market_info_settlement_asset(page: Page, vega: VegaService):
# 6002-MDET-206
page.get_by_test_id(market_title_test_id).get_by_text("Settlement asset").click()
tdai_id = vega.find_asset_id("tDAI")
tdai_id_short = tdai_id[:6] + "" + tdai_id[-4:]
fields = [
["ID", tdai_id_short],
["Type", "Builtin asset"],
["Name", "tDAI"],
["Symbol", "tDAI"],
["Decimals", "5"],
["Quantum", "0.00001"],
["Status", "Enabled"],
["Max faucet amount", "10,000,000,000.00"],
["Infrastructure fee account balance", "0.00"],
["Global reward pool account balance", "0.00"],
]
validate_info_section(page, fields)
def test_market_info_metadata(page: Page):
# 6002-MDET-207
page.get_by_test_id(market_title_test_id).get_by_text("Metadata").click()
fields = [
["Base", "BTC"],
]
validate_info_section(page, fields)
def test_market_info_risk_model(page: Page):
# 6002-MDET-208
page.get_by_test_id(market_title_test_id).get_by_text("Risk model").click()
fields = [
["Tau", "0.00011407711613050422"],
["Risk Aversion Parameter", "0.000001"],
["Sigma", "1"],
]
validate_info_section(page, fields)
def test_market_info_margin_scaling_factors(page: Page):
# 6002-MDET-209
page.get_by_test_id(market_title_test_id).get_by_text(
"Margin scaling factors"
).click()
fields = [
["Linear Slippage Factor", "0.001"],
["Quadratic Slippage Factor", "0"],
["Search Level", "1.1"],
["Initial Margin", "1.5"],
["Collateral Release", "1.7"],
]
validate_info_section(page, fields)
def test_market_info_risk_factors(page: Page):
# 6002-MDET-210
page.get_by_test_id(market_title_test_id).get_by_text("Risk factors").click()
fields = [
["Long", "0.05153"],
["Short", "0.05422"],
["Max Leverage Long", "19.036"],
["Max Leverage Short", "18.111"],
["Max Initial Leverage Long", "12.691"],
["Max Initial Leverage Short", "12.074"],
]
validate_info_section(page, fields)
def test_market_info_price_monitoring_bounds(page: Page):
# 6002-MDET-211
page.get_by_test_id(market_title_test_id).get_by_text(
"Price monitoring bounds 1"
).click()
expect(page.locator("p.col-span-1").nth(0)).to_contain_text(
"99.9999% probability price bounds"
)
expect(page.locator("p.col-span-1").nth(1)).to_contain_text("Within 86,400 seconds")
fields = [
["Highest Price", "138.66685 BTC"],
["Lowest Price", "83.11038 BTC"],
]
validate_info_section(page, fields)
def test_market_info_liquidity_monitoring_parameters(page: Page):
# 6002-MDET-212
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidity monitoring parameters"
).click()
fields = [
["Triggering Ratio", "0.7"],
["Time Window", "3,600"],
["Scaling Factor", "1"],
]
validate_info_section(page, fields)
# Liquidity resolves to 3 results
def test_market_info_liquidit(page: Page):
# 6002-MDET-213
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidity", exact=True
).click()
fields = [
["Target Stake", "5.82757 tDAI"],
["Supplied Stake", "10,000.00 tDAI"],
]
validate_info_section(page, fields)
def test_market_info_liquidity_price_range(page: Page):
# 6002-MDET-214
page.get_by_test_id(market_title_test_id).get_by_text(
"Liquidity price range"
).click()
fields = [
["Liquidity Price Range", "100% of mid price"],
["Lowest Price", "0.00 BTC"],
["Highest Price", "205.00 BTC"],
]
validate_info_section(page, fields)
def test_market_info_proposal(page: Page, vega: VegaService):
# 6002-MDET-301
page.get_by_test_id(market_title_test_id).get_by_text("Proposal").click()
first_link = (
page.get_by_test_id("accordion-content").get_by_test_id("external-link").first
)
second_link = (
page.get_by_test_id("accordion-content").get_by_test_id("external-link").nth(1)
)
expect(first_link).to_have_text("View governance proposal")
expect(first_link).to_have_attribute(
"href", re.compile(rf'(\/proposals\/{vega.find_market_id("BTC:DAI_2023")})')
)
expect(second_link).to_have_text("Propose a change to market")
# create regular expression that matches "/proposals/propose/update-market" string
expect(second_link).to_have_attribute(
"href", re.compile(r"(\/proposals\/propose\/update-market)")
)
def test_market_info_succession_line(page: Page, vega: VegaService):
page.get_by_test_id(market_title_test_id).get_by_text("Succession line").click()
market_id = vega.find_market_id("BTC:DAI_2023")
succession_line = page.get_by_test_id("succession-line-item")
expect(succession_line.get_by_test_id("external-link")).to_have_text("BTC:DAI_2023")
expect(succession_line.get_by_test_id("external-link")).to_have_attribute(
"href", re.compile(rf"(\/proposals\/{market_id})")
)
expect(page.get_by_test_id("succession-line-item-market-id")).to_have_text(
market_id
)

View File

@ -0,0 +1,88 @@
import pytest
from playwright.sync_api import expect, Page
@pytest.mark.usefixtures("page", "continuous_market", "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()
page.get_by_test_id("header-title").click()
# 6001-MARK-066
expect(page.get_by_test_id("market-selector")).to_be_visible()
# 6001-MARK-021
# 6001-MARK-022
# 6001-MARK-024
# 6001-MARK-025
btc_market = page.locator('[data-testid="market-selector-list"] a')
expect(btc_market.locator("h3")).to_have_text("BTC:DAI_2023Futr")
expect(btc_market.locator('[data-testid="market-selector-volume"]')).to_have_text(
"0.00"
)
expect(btc_market.locator('[data-testid="market-selector-price"]')).to_have_text(
"107.50 tDAI"
)
expect(btc_market.locator("span.rounded-md.leading-none")).to_be_visible()
expect(btc_market.locator("span.rounded-md.leading-none")).to_have_text("Futr")
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.parametrize(
"simple_market",
[
{
"custom_market_name": "APPL.MF21",
"custom_asset_name": "tUSDC",
"custom_asset_symbol": "tUSDC",
}
],
indirect=True,
)
def test_market_selector_filter(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("header-title").click()
# 6001-MARK-027
page.get_by_test_id("product-Spot").click()
expect(page.get_by_test_id("market-selector-list")).to_contain_text(
"Spot markets coming soon."
)
page.get_by_test_id("product-Perpetual").click()
expect(page.get_by_test_id("market-selector-list")).to_contain_text(
"No perpetual markets."
)
page.get_by_test_id("product-Future").click()
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(2)
# 6001-MARK-029
page.get_by_test_id("search-term").fill("btc")
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(1)
expect(page.locator('[data-testid="market-selector-list"] a').nth(0)).to_have_text(
"BTC:DAI_2023107.50 tDAI0.00"
)
page.get_by_test_id("search-term").clear()
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(2)
# 6001-MARK-030
# 6001-MARK-031
# 6001-MARK-032
# 6001-MARK-033
page.get_by_test_id("sort-trigger").click()
expect(page.get_by_test_id("sort-item-Gained")).to_have_text("Top gaining")
expect(page.get_by_test_id("sort-item-Gained")).to_be_visible()
expect(page.get_by_test_id("sort-item-Lost")).to_have_text("Top losing")
expect(page.get_by_test_id("sort-item-Lost")).to_be_visible()
expect(page.get_by_test_id("sort-item-New")).to_have_text("New markets")
expect(page.get_by_test_id("sort-item-New")).to_be_visible()
# 6001-MARK-028
page.get_by_test_id("sort-trigger").click(force=True)
page.get_by_test_id("asset-trigger").click()
page.get_by_role("menuitemcheckbox").nth(0).get_by_text("tDAI").click()
expect(page.locator('[data-testid="market-selector-list"] a')).to_have_count(1)
expect(page.locator('[data-testid="market-selector-list"] a').nth(0)).to_have_text(
"BTC:DAI_2023107.50 tDAI0.00"
)

View File

@ -0,0 +1,160 @@
import pytest
from playwright.sync_api import Page, expect
from fixtures.market import setup_continuous_market
from conftest import init_vega
market_names = ["ETHBTC.QM21", "BTCUSD.MF21", "SOLUSD", "AAPL.MF21"]
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
yield vega
@pytest.fixture(scope="module")
def create_markets(vega):
for market_name in market_names:
setup_continuous_market(vega, custom_market_name=market_name)
@pytest.mark.usefixtures("risk_accepted")
def test_table_headers(page: Page, create_markets):
page.goto(f"/#/markets/all")
headers = [
"Market",
"Description",
"Trading mode",
"Status",
"Mark price",
"24h volume",
"Settlement asset",
"Spread",
"",
]
page.wait_for_selector('[data-testid="tab-open-markets"]', state="visible")
page_headers = (
page.get_by_test_id("tab-open-markets").locator(".ag-header-cell-text").all()
)
for i, header in enumerate(headers):
expect(page_headers[i]).to_have_text(header)
@pytest.mark.usefixtures("risk_accepted")
def test_markets_tab(page: Page, create_markets):
page.goto(f"/#/markets/all")
expect(page.get_by_test_id("Open markets")).to_have_attribute(
"data-state", "active"
)
expect(page.get_by_test_id("Proposed markets")).to_have_attribute(
"data-state", "inactive"
)
expect(page.get_by_test_id("Closed markets")).to_have_attribute(
"data-state", "inactive"
)
@pytest.mark.usefixtures("risk_accepted")
def test_markets_content(page: Page, create_markets):
page.goto(f"/#/markets/all")
row_selector = page.locator(
'[data-testid="tab-open-markets"] .ag-center-cols-container .ag-row'
).first
instrument_code_locator = '[col-id="tradableInstrument.instrument.code"] [data-testid="stack-cell-primary"]'
# 6001-MARK-035
expect(row_selector.locator(instrument_code_locator)).to_have_text("ETHBTC.QM21")
# 6001-MARK-073
expect(row_selector.locator('[title="Future"]')).to_have_text("Futr")
# 6001-MARK-036
expect(
row_selector.locator('[col-id="tradableInstrument.instrument.name"]')
).to_have_text("ETHBTC.QM21")
# 6001-MARK-037
expect(row_selector.locator('[col-id="tradingMode"]')).to_have_text("Continuous")
# 6001-MARK-038
expect(row_selector.locator('[col-id="state"]')).to_have_text("Active")
# 6001-MARK-039
expect(row_selector.locator('[col-id="data.markPrice"]')).to_have_text("107.50")
# 6001-MARK-040
expect(row_selector.locator('[col-id="data.candles"]')).to_have_text("0.00")
# 6001-MARK-042
expect(
row_selector.locator(
'[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"]'
)
).to_have_text("tDAI")
expect(row_selector.locator('[col-id="data.bestBidPrice"]')).to_have_text("2")
# 6001-MARK-043
row_selector.locator(
'[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"] button'
).click()
expect(page.get_by_test_id("dialog-title")).to_have_text("Asset details - tDAI")
# 6001-MARK-019
page.get_by_test_id("close-asset-details-dialog").click()
@pytest.mark.usefixtures("risk_accepted")
def test_market_actions(page: Page, create_markets):
# 6001-MARK-044
# 6001-MARK-045
# 6001-MARK-046
# 6001-MARK-047
page.goto(f"/#/markets/all")
page.locator(
'.ag-pinned-right-cols-container [col-id="market-actions"]'
).first.locator("button").click()
actions = [
"Copy Market ID",
"View on Explorer",
"View settlement asset details",
]
action_elements = (
page.get_by_test_id("market-actions-content").get_by_role("menuitem").all()
)
for i, action in enumerate(actions):
expect(action_elements[i]).to_have_text(action)
@pytest.mark.usefixtures("risk_accepted")
def test_sort_markets(page: Page, create_markets):
# 6001-MARK-064
page.goto(f"/#/markets/all")
sorted_market_names = [
"AAPL.MF21",
"BTCUSD.MF21",
"ETHBTC.QM21",
"SOLUSD",
]
page.locator('.ag-header-row [col-id="tradableInstrument.instrument.code"]').click()
for i, market_name in enumerate(sorted_market_names):
expect(
page.locator(
f'[row-index="{i}"] [col-id="tradableInstrument.instrument.name"]'
)
).to_have_text(market_name)
@pytest.mark.usefixtures("risk_accepted")
def test_drag_and_drop_column(page: Page, create_markets):
# 6001-MARK-065
page.goto(f"/#/markets/all")
col_instrument_code = '.ag-header-row [col-id="tradableInstrument.instrument.code"]'
page.locator(col_instrument_code).drag_to(
page.locator('.ag-header-row [col-id="data.bestBidPrice"]')
)
expect(page.locator(col_instrument_code)).to_have_attribute("aria-colindex", "8")

View File

@ -0,0 +1,36 @@
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
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
page.goto("/#/markets/all")
yield page
def test_no_open_markets(page: Page):
# 6001-MARK-034
page.get_by_test_id("Open markets").click()
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No markets")
def test_no_closed_markets(page: Page):
page.get_by_test_id("Closed markets").click()
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No markets")
def test_no_proposed_markets(page: Page):
# 6001-MARK-061
page.get_by_test_id("Proposed markets").click()
expect(page.locator(".ag-overlay-wrapper")).to_have_text("No proposed markets")

View File

@ -0,0 +1,132 @@
from math import exp
import pytest
import vega_sim.api.governance as governance
import re
from collections import namedtuple
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
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_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"]'
@pytest.fixture(scope="module")
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
market_id = setup_simple_market(vega, approve_proposal=False)
# approve market
governance.approve_proposal(
key_name=MM_WALLET.name,
proposal_id=market_id,
wallet=vega.wallet,
)
return market_id
@pytest.mark.usefixtures("risk_accepted")
def test_can_see_table_headers(proposed_market, page: Page):
page.goto("/#/markets/all")
page.click('[data-testid="Proposed markets"]')
# Test that you can see table headers
headers = [
"Market",
"Settlement asset",
"State",
"Parent market",
"Voting",
"Closing date",
"Enactment date",
"",
]
header_elements = page.locator(".ag-header-cell-text")
for i, header in enumerate(headers):
assert header_elements.nth(i).inner_text() == header
@pytest.mark.usefixtures("risk_accepted")
def test_renders_markets_correctly(proposed_market, page: Page):
page.goto(f"/#/markets/all")
page.click('[data-testid="Proposed markets"]')
row = page.locator(row_selector)
# 6001-MARK-049
expect(row.locator(col_market_id)).to_have_text("BTC:DAI_2023")
# 6001-MARK-051
expect(row.locator('[col-id="asset"]')).to_have_text("tDAI")
# 6001-MARK-052
# 6001-MARK-053
expect(row.locator('[col-id="state"]')).to_have_text("Open")
expect(
row.locator('[col-id="terms.change.successorConfiguration.parentMarketId"]')
).to_have_text("-")
# 6001-MARK-054
# 6001-MARK-055
expect(row.get_by_test_id("vote-progress-bar-against")).to_be_visible()
# 6001-MARK-056
expect(row.locator('[col-id="closing-date"]')).not_to_be_empty()
# 6001-MARK-057
expect(row.locator('[col-id="enactment-date"]')).not_to_be_empty
# 6001-MARK-058
page.get_by_test_id("dropdown-menu").click()
dropdown_content = '[data-testid="proposal-actions-content"]'
first_item_link = (
page.locator(f"{dropdown_content} [role='menuitem']").nth(0).locator("a")
)
# 6001-MARK-059
expect(first_item_link).to_contain_text("View proposal")
expect(first_item_link).to_have_attribute(
"href",
re.compile(r"\/proposals\/[a-f0-9]{64}$"),
)
# temporary skip
# 6001-MARK-060
# proposed_markets_tab = page.get_by_test_id("tab-proposed-markets")
# external_links = proposed_markets_tab.locator("font-alpha")
# last_link = external_links.last
# assert last_link.inner_text() == 'Propose a new market'
# expected_href = f"https://governance.stagnet1.vega.rocks/proposals/propose/new-market"
# assert last_link.get_attribute('href') == expected_href
@pytest.mark.usefixtures("risk_accepted")
def test_can_drag_and_drop_columns(proposed_market, page: Page):
# 6001-MARK-063
page.goto("/#/markets/all")
page.click('[data-testid="Proposed markets"]')
col_market = page.locator('[col-id="market"]').first
col_vote = page.locator('[col-id="voting"]').first
col_market.drag_to(col_vote)
# Check the attribute of the dragged element
attribute_value = col_market.get_attribute("aria-colindex")
assert attribute_value != "1"

View File

@ -0,0 +1,131 @@
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from actions.vega import submit_order
from fixtures.market import setup_simple_market
from conftest import init_vega
from actions.utils import wait_for_toast_confirmation
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
TERMINATE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, TERMINATE_WALLET]
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module")
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(
key_name=MM_WALLET.name,
market_id=simple_market,
commitment_amount=100,
fee=0.002,
is_amendment=False,
)
vega.submit_order(
market_id=simple_market,
trading_key=MM_WALLET.name,
side="SIDE_BUY",
order_type="TYPE_LIMIT",
price=1 - 0.0005,
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
vega.submit_order(
market_id=simple_market,
trading_key=MM_WALLET.name,
side="SIDE_SELL",
order_type="TYPE_LIMIT",
price=1 + 0.0005,
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
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_WALLET2.name, simple_market, "SIDE_SELL", 1, 1)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# add orders that change the price so that it goes beyond the limits of price monitoring
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 110)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 90)
submit_order(vega, MM_WALLET.name, simple_market, "SIDE_SELL", 100, 105)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 100, 95)
submit_order(vega, MM_WALLET2.name, simple_market, "SIDE_BUY", 1, 105)
vega.forward("10s")
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):
page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-size").clear()
page.get_by_test_id("order-size").type("1")
page.get_by_test_id("order-price").clear()
page.get_by_test_id("order-price").type("110")
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_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_be_visible()
page.get_by_test_id("order-tif").select_option("Good 'til Cancelled (GTC)")
expect(page.get_by_test_id("deal-ticket-error-message-tif")).not_to_be_visible()
page.get_by_test_id("place-order").click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.get_by_test_id("All").click()
expect(page.get_by_role("row").nth(2)).to_contain_text(
"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):
page.goto(f"/#/markets/{simple_market}")
page.get_by_test_id("order-type-Market").click()
page.get_by_test_id("order-size").clear()
page.get_by_test_id("order-size").type("1")
# 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_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_be_visible()

View File

@ -0,0 +1,174 @@
import pytest
import vega_sim.api.governance as governance
import re
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService, PeggedOrder
import vega_sim.proto.vega as vega_protos
import vega_sim.api.governance as governance
from actions.vega import submit_order
from fixtures.market import setup_continuous_market
from datetime import datetime
from datetime import timedelta
from vega_sim.service import MarketStateUpdateType
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
GOVERNANCE_WALLET = WalletConfig("FJMKnwfZdd48C8NqvYrG", "bY3DxwtsCstMIIZdNpKs")
wallets = [MM_WALLET, MM_WALLET2, GOVERNANCE_WALLET]
@pytest.mark.usefixtures("vega", "page", "proposed_market", "risk_accepted")
def test_market_lifecycle(proposed_market, vega: VegaService, page: Page):
trading_mode = page.get_by_test_id("market-trading-mode").get_by_test_id(
"item-value"
)
market_state = page.get_by_test_id("market-state").get_by_test_id("item-value")
# setup market in proposed step, without liquidity provided
market_id = proposed_market
page.goto(f"/#/markets/{market_id}")
# check that market is in proposed state
expect(trading_mode).to_have_text("No trading")
expect(market_state).to_have_text("Proposed")
# approve market
governance.approve_proposal(
key_name=MM_WALLET.name,
proposal_id=market_id,
wallet=vega.wallet,
)
# "wait" for market to be approved and enacted
vega.forward("60s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# check that market is in pending state
expect(trading_mode).to_have_text("Opening auction")
expect(market_state).to_have_text("Pending")
# Add liquidity and place some orders. Orders should match to produce the uncrossing price. A market can only move from opening auction to continuous trading when the enactment date has passed, there is sufficient liquidity and an uncrossing price is produced.
vega.submit_simple_liquidity(
key_name=MM_WALLET.name,
market_id=market_id,
commitment_amount=10000,
fee=0.000,
is_amendment=False,
)
vega.submit_order(
market_id=market_id,
trading_key=MM_WALLET.name,
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
vega.submit_order(
market_id=market_id,
trading_key=MM_WALLET.name,
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=1),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=99,
)
submit_order(vega, MM_WALLET.name, market_id, "SIDE_SELL", 1, 110)
submit_order(vega, MM_WALLET2.name, market_id, "SIDE_BUY", 1, 90)
submit_order(vega, MM_WALLET.name, market_id, "SIDE_SELL", 1, 105)
submit_order(vega, MM_WALLET2.name, market_id, "SIDE_BUY", 1, 95)
submit_order(vega, MM_WALLET.name, market_id, "SIDE_SELL", 1, 100)
submit_order(vega, MM_WALLET2.name, market_id, "SIDE_BUY", 1, 100)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# check market state is now active and trading mode is continuous
expect(trading_mode).to_have_text("Continuous")
expect(market_state).to_have_text("Active")
# put invalid oracle to trigger market termination
governance.submit_oracle_data(
wallet=vega.wallet,
payload={"trading.terminated": "true"},
key_name=GOVERNANCE_WALLET.name,
)
vega.forward("60s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# market state should be changed to "Trading Terminated" because of the invalid oracle
expect(trading_mode).to_have_text("No trading")
expect(market_state).to_have_text("Trading Terminated")
# settle market
vega.submit_termination_and_settlement_data(
settlement_key=GOVERNANCE_WALLET.name,
settlement_price=100,
market_id=market_id,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# check market state is now settled
expect(trading_mode).to_have_text("No trading")
expect(market_state).to_have_text("Settled")
""" @pytest.mark.usefixtures("page", "risk_accepted", "continuous_market")
def test_market_closing_banners(page: Page, continuous_market, vega: VegaService):
market_id = continuous_market
page.goto(f"/#/markets/{market_id}")
proposalID = vega.update_market_state(
continuous_market,
"mm",
MarketStateUpdateType.Terminate,
approve_proposal=False,
vote_enactment_time = datetime.now() + timedelta(weeks=1),
forward_time_to_enactment = False,
price=107,
)
may_close_warning_pattern = r"TRADING ON MARKET BTC:DAI_2023 MAY STOP ON \d+ \w+\.\s*THERE IS OPEN PROPOSAL TO CLOSE THIS MARKET\.\nProposed final price is 107\.00 BTC\.\nView proposal"
match_result = re.fullmatch(may_close_warning_pattern, page.locator(".grow").inner_text())
assert match_result is not None
vega.update_market_state(
continuous_market,
"mm",
MarketStateUpdateType.Terminate,
approve_proposal=False,
vote_enactment_time = datetime.now() + timedelta(weeks=1),
forward_time_to_enactment = False,
price=110,
)
expect(page.locator(".grow")).to_have_text("Trading on Market BTC:DAI_2023 may stop. There are open proposals to close this marketView proposals")
governance.approve_proposal(
proposal_id=proposalID,
wallet=vega.wallet,
key_name="mm"
)
vega.forward("60s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
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
"""

View File

@ -0,0 +1,111 @@
import pytest
from playwright.sync_api import Page, expect, Locator
from conftest import init_page, init_vega
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
yield vega
# we can reuse single page instance in all tests
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
yield page
@pytest.mark.usefixtures("risk_accepted")
def test_network_switcher(page: Page):
page.goto("/#/disclaimer")
navbar = page.locator('nav[aria-label="Main"]')
assert_network_switcher(navbar)
@pytest.mark.usefixtures("risk_accepted")
def test_navbar_pages(page: Page):
page.goto("/#/disclaimer")
navbar = page.locator('nav[aria-label="Main"]')
assert_links(navbar)
@pytest.mark.usefixtures("risk_accepted")
def test_navigation_mobile(page: Page):
page.goto("/#/disclaimer")
page.set_viewport_size({"width": 800, "height": 1040})
navbar = page.locator('nav[aria-label="Main"]')
# region navigation
burger = navbar.get_by_test_id("navbar-mobile-burger")
expect(burger).to_be_visible()
burger.click()
menu = navbar.get_by_test_id("navbar-menu-content")
expect(menu).to_be_visible()
assert_links(menu)
assert_network_switcher(menu)
menu.get_by_role("button", name="Close menu").click()
# endregion
# region wallet
wallet_button = navbar.get_by_test_id("navbar-mobile-wallet")
expect(wallet_button).to_be_visible()
wallet_button.click()
dialog = page.get_by_test_id("dialog-content")
expect(dialog.get_by_test_id("wallet-dialog-title")).to_be_visible()
# endregion
def assert_links(container: Locator):
pages = [
{"name": "Markets", "href": "#/markets"},
{"name": "Trading", "href": "#/markets/"},
{"name": "Portfolio", "href": "#/portfolio"},
]
for page in pages:
link = container.get_by_role("link", name=page["name"])
expect(link).to_be_visible()
expect(link).to_have_attribute("href", page["href"])
# False indicates external link configured by env var
resource_pages = [
{"name": "Docs", "href": False},
{"name": "Give Feedback", "href": False},
{"name": "Disclaimer", "href": "#/disclaimer"},
]
container.get_by_role("button", name="Resources").click()
dropdown = container.get_by_test_id("navbar-content-resources")
for resource_page in resource_pages:
page_name = resource_page["name"]
page_href = resource_page["href"]
link = dropdown.get_by_role("link", name=page_name)
expect(link).to_be_visible()
if not page_href:
href = link.get_attribute("href")
expect(link).to_have_attribute("target", "_blank")
assert len(href) >= 0, f"href for {page_name} is empty"
else:
expect(link).to_have_attribute("href", page_href)
def assert_network_switcher(container: Locator):
network_switcher_trigger = container.get_by_test_id(
"navbar-network-switcher-trigger"
)
# 0006-NETW-002
expect(network_switcher_trigger).to_have_text = "Fairground testnet"
network_switcher_trigger.click()
dropdown = container.get_by_test_id("navbar-content-network-switcher")
expect(dropdown).to_be_visible()
links = dropdown.get_by_role("link")
expect(links).to_have_count(2)
mainnet_link = container.get_by_role("link", name="Mainnet")
expect(mainnet_link).to_be_visible()
# 0006-NETW-003
expect(mainnet_link).to_have_attribute("href", "https://console.vega.xyz")
expect(container.get_by_role("link", name="Fairground testnet")).to_be_visible()

View File

@ -0,0 +1,64 @@
import pytest
import re
from playwright.sync_api import expect, Page
from vega_sim.service import VegaService
from actions.vega import submit_order
order_details = [
("order-market-label", "Market", "order-market-value", "BTC:DAI_2023"),
("order-side-label", "Side", "order-side-value", "Short"),
("order-type-label", "Type", "order-type-value", "Limit"),
("order-price-label", "Price", "order-price-value", "101.00"),
("order-size-label", "Size", "order-size-value", "-102"),
("order-remaining-label", "Remaining", "order-remaining-value", "-2"),
("order-status-label", "Status", "order-status-value", "Active"),
("order-id-label", "Order ID", "order-id-value", r"^.{10}\u2026.+Copy$", True),
(
"order-created-label",
"Created",
"order-created-value",
r"^\d{1,2}/\d{1,2}/\d{4}, \d{1,2}:\d{2}:\d{2}$",
True,
),
(
"order-time-in-force-label",
"Time in force",
"order-time-in-force-value",
"Good 'til Cancelled (GTC)",
),
]
def verify_order_label(page: Page, test_id: str, expected_text: str):
element = page.get_by_test_id(test_id)
expect(element).to_be_visible()
expect(element).to_have_text(expected_text)
def verify_order_value(
page: Page, test_id: str, expected_text: str, is_regex: bool = False
):
element = page.get_by_test_id(test_id)
expect(element).to_be_visible()
if is_regex:
actual_text = element.text_content()
assert re.match(
expected_text, actual_text
), f"Expected {expected_text}, but got {actual_text}"
else:
expect(element).to_have_text(expected_text)
@pytest.mark.skip("tbd")
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
def test_order_details_are_correctly_displayed(
continuous_market, vega: VegaService, page: Page
):
page.goto(f"/#/markets/{continuous_market}")
submit_order(vega, "Key 1", vega.all_markets()[0].id, "SIDE_SELL", 102, 101, 2, 1)
page.get_by_test_id("Open").click()
page.get_by_test_id("icon-kebab").click()
page.get_by_test_id("view-order").click()
for detail in order_details:
label_id, label_text, value_id, value_text, is_regex = (*detail, False)[:5]
verify_order_label(page, label_id, label_text)
verify_order_value(page, value_id, value_text, is_regex)

View File

@ -0,0 +1,191 @@
import pytest
import re
from playwright.sync_api import expect, Page
from vega_sim.service import VegaService
from playwright.sync_api import expect
from actions.vega import submit_order
import logging
logger = logging.getLogger()
# Could be turned into a helper function in the future.
def verify_data_grid(page, data_test_id, expected_pattern):
page.get_by_test_id(data_test_id).click()
# Required so that we can get liquidation price
if data_test_id == "Positions":
wait_for_graphql_response(page, "EstimatePosition")
expect(
page.locator(
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
)
).to_be_visible()
actual_text = page.locator(
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
).text_content()
lines = actual_text.strip().split("\n")
for expected, actual in zip(expected_pattern, lines):
# We are using regex so that we can run tests in different timezones.
if re.match(r"^\\d", expected): # check if it's a regex
if re.search(expected, actual):
logger.info(f"Matched: {expected} == {actual}")
else:
logger.info(f"Not Matched: {expected} != {actual}")
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
else: # it's not a regex, so we escape it
if re.search(re.escape(expected), actual):
logger.info(f"Matched: {expected} == {actual}")
else:
logger.info(f"Not Matched: {expected} != {actual}")
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
# Required so that we can get liquidation price - Could also become a helper
def wait_for_graphql_response(page, query_name, timeout=5000):
response_data = {}
def handle_response(route, request):
if "graphql" in request.url:
response = request.response()
if response is not None:
json_response = response.json()
if json_response and "data" in json_response:
data = json_response["data"]
if query_name in data:
response_data["data"] = data
route.continue_()
return
route.continue_()
# Register the route handler
page.route("**", handle_response)
# Wait for the response data to be populated
page.wait_for_timeout(timeout)
# Unregister the route handler
page.unroute("**", handle_response)
def submit_order(vega, wallet_name, market_id, side, volume, price):
vega.submit_order(
trading_key=wallet_name,
market_id=market_id,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side=side,
volume=volume,
price=price,
)
@pytest.mark.usefixtures(
"vega", "page", "opening_auction_market", "auth", "risk_accepted"
)
def test_limit_order_trade_open_order(
opening_auction_market, vega: VegaService, page: Page
):
market_id = opening_auction_market
submit_order(vega, "Key 1", market_id, "SIDE_BUY", 1, 110)
page.goto(f"/#/markets/{market_id}")
# Assert that the user order is displayed on the orderbook
orderbook_trade = page.get_by_test_id("price-11000000").nth(1)
# 6003-ORDB-001
# 6003-ORDB-002
expect(orderbook_trade).to_be_visible()
expected_open_order = [
"BTC:DAI_2023",
"+1",
"Limit",
"Active",
"0/1",
"110.00",
"Good 'til Cancelled (GTC)",
r"\d{1,2}/\d{1,2}/\d{4},\s*\d{1,2}:\d{2}:\d{2}\s*(?:AM|PM)",
"-",
]
logger.info("Assert Open orders:")
verify_data_grid(page, "Open", expected_open_order)
@pytest.mark.usefixtures("vega", "page", "continuous_market", "auth", "risk_accepted")
def test_limit_order_trade_open_position(continuous_market, page: Page):
page.goto(f"/#/markets/{continuous_market}")
primary_id = "stack-cell-primary"
secondary_id = "stack-cell-secondary"
position = {
"market_code": "BTC:DAI_2023",
"settlement_asset": "tDAI",
"product_type": "Futr",
"size": "+1",
"notional": "107.50",
"average_entry_price": "107.50",
"mark_price": "107.50",
"margin": "8.50269",
"leverage": "1.0x",
"liquidation": "0.00",
"realised_pnl": "0.00",
"unrealised_pnl": "0.00",
}
tab = page.get_by_test_id("tab-positions")
table = tab.locator(".ag-center-cols-container")
# 7004-POSI-001
# 7004-POSI-002
market = table.locator("[col-id='marketCode']")
expect(market.get_by_test_id(primary_id)).to_have_text(position["market_code"])
expect(market.get_by_test_id(secondary_id)).to_have_text(
position["settlement_asset"] + position["product_type"]
)
size_and_notional = table.locator("[col-id='openVolume']")
expect(size_and_notional.get_by_test_id(primary_id)).to_have_text(position["size"])
expect(size_and_notional.get_by_test_id(secondary_id)).to_have_text(
position["notional"]
)
entry_and_mark = table.locator("[col-id='markPrice']")
expect(entry_and_mark.get_by_test_id(primary_id)).to_have_text(
position["average_entry_price"]
)
expect(entry_and_mark.get_by_test_id(secondary_id)).to_have_text(
position["mark_price"]
)
margin_and_leverage = table.locator("[col-id='margin']")
expect(margin_and_leverage.get_by_test_id(primary_id)).to_have_text(
position["margin"]
)
expect(margin_and_leverage.get_by_test_id(secondary_id)).to_have_text(
position["leverage"]
)
liquidation = table.locator("[col-id='liquidationPrice']")
expect(liquidation.get_by_test_id("liquidation-price")).to_have_text(
position["liquidation"]
)
realisedPNL = table.locator("[col-id='realisedPNL']")
expect(realisedPNL).to_have_text(position["realised_pnl"])
unrealisedPNL = table.locator("[col-id='unrealisedPNL']")
expect(unrealisedPNL).to_have_text(position["unrealised_pnl"])
@pytest.mark.usefixtures("vega", "page", "continuous_market", "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
page.get_by_test_id("Orderbook").click()
price_element = page.get_by_test_id("price-11000000").nth(1)
# 6003-ORDB-010
expect(price_element).to_be_hidden()

View File

@ -0,0 +1,414 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService, PeggedOrder
from conftest import auth_setup, init_page, init_vega, risk_accepted_setup
from fixtures.market import setup_continuous_market, setup_simple_market
from actions.utils import wait_for_toast_confirmation
order_tab = "tab-orders"
@pytest.fixture(scope="module")
def vega(request):
with init_vega(request) as vega:
yield vega
@pytest.fixture(scope="module", autouse=True)
def markets(vega: VegaService):
market_1 = setup_continuous_market(
vega,
custom_market_name="market-1",
)
market_2 = setup_continuous_market(
vega,
custom_market_name="market-2",
)
market_3 = setup_continuous_market(
vega,
custom_market_name="market-3",
)
market_4 = setup_continuous_market(
vega,
custom_market_name="market-4",
)
market_5 = setup_simple_market(
vega,
custom_market_name="market-5",
)
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=130,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=100,
price=88,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_1,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=1e10,
price=130,
wait=False,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_IOC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=100,
price=104,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_3,
time_in_force="TIME_IN_FORCE_GTT",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=120,
expires_at=vega.get_blockchain_time() + 5 * 1e9,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_MID", offset=5),
time_in_force="TIME_IN_FORCE_GTC",
volume=20,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_BUY",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_BID", offset=10),
time_in_force="TIME_IN_FORCE_GTC",
volume=40,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
market_id=market_4,
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
market_id=market_5,
trading_key="Key 1",
side="SIDE_SELL",
order_type="TYPE_LIMIT",
pegged_order=PeggedOrder(reference="PEGGED_REFERENCE_BEST_ASK", offset=15),
wait=False,
time_in_force="TIME_IN_FORCE_GTC",
volume=60,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=150,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_2,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_SELL",
volume=10,
price=160,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
vega.submit_order(
trading_key="Key 1",
market_id=market_3,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=10,
price=60,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
@pytest.fixture(scope="module")
def page(vega, browser, request):
with init_page(vega, browser, request) as page:
risk_accepted_setup(page)
auth_setup(vega, page)
page.goto("/")
page.get_by_test_id("All").click()
yield page
# close toast that is still opened after test
@pytest.fixture(autouse=True)
def after_each(page: Page):
yield
if page.get_by_test_id("toast-close").is_visible():
page.get_by_test_id("toast-close").click()
# 7002-SORD-040 (as all the tests are about status)
def test_order_sorted(page: Page):
# 7003-MORD-002
orders_update_date = page.locator(
'.ag-center-cols-container [col-id="updatedAt"]'
).all_text_contents()
orders_update_date_sorted = sorted(orders_update_date, reverse=True)
assert all([a == b for a, b in zip(orders_update_date, orders_update_date_sorted)])
def test_order_status_active(page: Page):
# 7002-SORD-041
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-2Futr" + "0" + "-10" + "Limit" + "Active" + "150.00" + "GTC"
)
def test_status_expired(page: Page):
# 7002-SORD-042
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-3Futr" + "0" + "-10" + "Limit" + "Expired" + "120.00" + "GTT:"
)
def test_order_status_Stopped(page: Page):
# 7002-SORD-044
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-1Futr" + "0" + "-100" + "Limit" + "Stopped" + "130.00" + "IOC"
)
def test_order_status_partially_filled(page: Page):
# 7002-SORD-045
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-2Futr" + "99" + "+100" + "Limit" + "Partially Filled" + "104.00" + "IOC"
)
def test_order_status_filled(page: Page):
# 7002-SORD-046
# 7003-MORD-020
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-1Futr" + "100" + "-100" + "Limit" + "Filled" + "88.00" + "GTC"
)
def test_order_status_rejected(page: Page):
# 7002-SORD-047
# 7003-MORD-018
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-1Futr"
+ "0"
+ "-10,000,000,000"
+ "Limit"
+ "Rejected: Margin check failed"
+ "130.00"
+ "GTC"
)
def test_order_status_parked(page: Page):
# 7002-SORD-048
# 7003-MORD-016
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-5Futr"
+ "0"
+ "-60"
+ "Ask + 15.00 Peg limit"
+ "Parked"
+ "0.00"
+ "GTC"
)
def test_order_status_pegged_ask(page: Page):
# 7003-MORD-016
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-4Futr"
+ "0"
+ "-60"
+ "Ask + 15.00 Peg limit"
+ "Active"
+ "125.00"
+ "GTC"
)
def test_order_status_pegged_bid(page: Page):
# 7003-MORD-016
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-4Futr"
+ "0"
+ "+40"
+ "Bid - 10.00 Peg limit"
+ "Active"
+ "85.00"
+ "GTC"
)
def test_order_status_pegged_mid(page: Page):
# 7003-MORD-016
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-4Futr"
+ "0"
+ "+20"
+ "Mid - 5.00 Peg limit"
+ "Active"
+ "97.50"
+ "GTC"
)
def test_order_amend_order(vega: VegaService, page: Page):
# 7002-SORD-053
# 7003-MORD-012
# 7003-MORD-014
# 7003-MORD-015
page.get_by_test_id("edit").nth(1).click()
page.locator("#limitPrice").fill("170")
page.locator("#size").fill("15")
page.get_by_role("button", name="Update").click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-2Futr" + "0" + "-15" + "Limit" + "Active" + "170.00" + "GTC"
)
def test_order_cancel_single_order(vega: VegaService, page: Page):
# 7003-MORD-009
# 7003-MORD-010
# 7003-MORD-011
# 7002-SORD-043
page.get_by_test_id("cancel").first.click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_test_id(order_tab)).to_contain_text(
"market-3Futr" + "0" + "+10" + "Limit" + "Cancelled" + "60.00" + "GTC"
)
def test_order_cancel_all_orders(vega: VegaService, page: Page):
# 7003-MORD-009
# 7003-MORD-010
# 7003-MORD-011
# 7002-SORD-043
page.get_by_test_id("cancelAll").click()
wait_for_toast_confirmation(page, timeout=5000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(page.get_by_test_id("cancelAll")).not_to_be_visible()
expect(page.get_by_test_id("cancel")).not_to_be_visible()
expect(
page.locator('.ag-cell[col-id="status"]', has_text="Cancelled")
).to_have_count(7)

View File

@ -0,0 +1,272 @@
import pytest
from collections import namedtuple
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from typing import List
from actions.vega import submit_order, submit_liquidity, submit_multiple_orders
from conftest import init_vega
from fixtures.market import setup_simple_market
# Defined namedtuples
WalletConfig = namedtuple("WalletConfig", ["name", "passphrase"])
# Wallet Configurations
MM_WALLET = WalletConfig("mm", "pin")
MM_WALLET2 = WalletConfig("mm2", "pin2")
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
yield vega
@pytest.fixture(scope="module")
def setup_market(vega):
market_id = setup_simple_market(vega)
submit_liquidity(vega, MM_WALLET.name, market_id)
submit_multiple_orders(
vega,
MM_WALLET.name,
market_id,
"SIDE_SELL",
[[10, 130.005], [3, 130], [7, 120], [5, 110], [2, 105]],
)
submit_multiple_orders(
vega,
MM_WALLET2.name,
market_id,
"SIDE_BUY",
[[10, 69.995], [5, 70], [5, 85], [3, 90], [3, 95]],
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return [
vega,
market_id,
]
# these values don't align with the multiple orders above as
# creating a trade triggers the liquidity provision
orderbook_content = [
[130.00500, 10, 94],
[130.00000, 3, 84],
[120.00000, 7, 81],
[110.00000, 5, 74],
[105.00000, 2, 69],
[101.00000, 67, 67],
# mid
[99.00000, 102, 102],
[95.00000, 3, 105],
[90.00000, 3, 108],
[85.00000, 5, 113],
[70.00000, 5, 118],
[69.99500, 10, 128],
]
def verify_orderbook_grid(
page: Page, content: List[List[float]], last_trade_price: float = False
):
rows = page.locator("[data-testid$=-rows-container]").all()
for row_index, content_row in enumerate(content):
cells = rows[row_index].locator("button").all()
for cell_index, content_cell in enumerate(content_row):
assert float(cells[cell_index].text_content()) == content_cell
def verify_prices_descending(page: Page):
prices_locator = page.get_by_test_id("tab-orderbook").locator(
'[data-testid^="price-"]'
)
prices_locator.first.wait_for(state="visible")
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")
def test_orderbook_grid_content(setup_market, page: Page):
vega = setup_market[0]
market_id = setup_market[1]
# Create a so that lastTradePrice is shown in the mid section
# of the book
matching_order = [1, 100]
submit_order(
vega,
MM_WALLET.name,
market_id,
"SIDE_SELL",
matching_order[0],
matching_order[1],
)
submit_order(
vega,
MM_WALLET2.name,
market_id,
"SIDE_BUY",
matching_order[0],
matching_order[1],
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# 6003-ORDB-001
# 6003-ORDB-002
# 6003-ORDB-003
# 6003-ORDB-004
# 6003-ORDB-005
# 6003-ORDB-006
# 6003-ORDB-007
page.goto(f"/#/markets/{market_id}")
page.locator("[data-testid=Orderbook]").click()
# 6003-ORDB-013
assert (
float(page.locator("[data-testid*=last-traded]").text_content())
== matching_order[1]
)
# 6003-ORDB-011
# get the spread text trimming off the parentheses on either end
spread_text = page.locator("[data-testid=spread]").text_content()[1:-1]
assert (
# TODO: figure out how to not have hardcoded value
spread_text
== "2.00"
)
verify_orderbook_grid(page, orderbook_content)
verify_prices_descending(page)
@pytest.mark.usefixtures("page", "risk_accepted")
def test_orderbook_resolution_change(setup_market, page: Page):
market_id = setup_market[1]
# 6003-ORDB-008
orderbook_content_0_00 = [
[130.01, 10, 94],
[130.00, 3, 84],
[120.00, 7, 81],
[110.00, 5, 74],
[105.00, 2, 69],
[101.00, 67, 67],
# mid
[99.00, 102, 102],
[95.00, 3, 105],
[90.00, 3, 108],
[85.00, 5, 113],
[70.00, 15, 128],
]
orderbook_content_10 = [
[130, 13, 94],
[120, 7, 81],
[110, 7, 74],
[100, 67, 67],
# mid
[100, 105, 105],
[90, 8, 113],
[70, 15, 128],
]
orderbook_content_100 = [
[100, 94, 94],
# mid
[100, 128, 128],
]
resolutions = [
["0.00", orderbook_content_0_00],
["10", orderbook_content_10],
["100", orderbook_content_100],
]
page.goto(f"/#/markets/{market_id}")
# temporary skip
# for resolution in resolutions:
# page.get_by_test_id("resolution").click()
# page.get_by_role("menu").get_by_text(resolution[0], exact=True).click()
# verify_orderbook_grid(page, resolution[1])
@pytest.mark.usefixtures("page", "risk_accepted")
def test_orderbook_price_size_copy(setup_market, page: Page):
market_id = setup_market[1]
# 6003-ORDB-009
prices = page.get_by_test_id("tab-orderbook").locator('[data-testid^="price-"]')
volumes = page.get_by_test_id("tab-orderbook").locator('[data-testid*="-vol-"]')
page.goto(f"/#/markets/{market_id}")
prices.first.wait_for(state="visible")
for price in prices.all():
price.click()
expect(page.get_by_test_id("order-price")).to_have_value(price.text_content())
for volume in volumes.all():
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")
def test_orderbook_price_movement(setup_market, page: Page):
vega = setup_market[0]
market_id = setup_market[1]
page.goto(f"/#/markets/{market_id}")
page.locator("[data-testid=Orderbook]").click()
book_el = page.locator("[data-testid=orderbook-grid-element]")
# no arrow shown on load
expect(book_el.locator("[data-testid^=icon-arrow]")).not_to_be_attached()
matching_order_1 = [1, 101]
submit_order(
vega,
MM_WALLET2.name,
market_id,
"SIDE_BUY",
matching_order_1[0],
matching_order_1[1],
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# 6003-ORDB-013
expect(book_el.locator("[data-testid=icon-arrow-up]")).to_be_attached()
assert (
float(page.locator("[data-testid*=last-traded]").text_content())
== matching_order_1[1]
)
matching_order_2 = [1, 99]
submit_order(
vega,
MM_WALLET2.name,
market_id,
"SIDE_SELL",
matching_order_2[0],
matching_order_2[1],
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expect(book_el.locator("[data-testid=icon-arrow-down]")).to_be_attached()
assert (
float(page.locator("[data-testid*=last-traded]").text_content())
== matching_order_2[1]
)

View File

@ -0,0 +1,143 @@
import pytest
from playwright.sync_api import Page
from vega_sim.service import VegaService
from actions.vega import submit_order
def wait_for_graphql_response(page, query_name, timeout=5000):
response_data = {}
def handle_response(route, request):
if "graphql" in request.url:
response = request.response()
if response is not None:
json_response = response.json()
if json_response and "data" in json_response:
data = json_response["data"]
if query_name in data:
response_data["data"] = data
route.continue_()
return
route.continue_()
# Register the route handler
page.route("**", handle_response)
# Wait for the response data to be populated
page.wait_for_timeout(timeout)
# Unregister the route handler
page.unroute("**", handle_response)
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")
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)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.goto(f"/#/markets/{continuous_market}")
# Loss Trading unrealised
row = (
page.get_by_test_id("tab-positions")
.locator(".ag-center-cols-container .ag-row")
.nth(0)
)
realised_pnl = row.locator("[col-id='realisedPNL']")
unrealised_pnl = row.locator("[col-id='unrealisedPNL']")
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(unrealised_pnl, "rgb(236, 0, 60)", "-4.00")
# profit Trading unrealised
page.get_by_test_id("manage-vega-wallet").click()
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(unrealised_pnl, "rgb(1, 145, 75)", "4.00")
# neutral Trading unrealised
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(2).click(position={ "x": 0, "y": 0}, force=True)
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
# Portfolio Unrealised
page.get_by_test_id("manage-vega-wallet").click(force=True)
page.get_by_role("link", name="Portfolio").click()
page.get_by_test_id("Positions").click()
wait_for_graphql_response(page, "EstimatePosition")
page.wait_for_selector(
'[data-testid="tab-positions"] .ag-center-cols-container .ag-row',
state="visible",
)
key_1 = page.query_selector(
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="Key 1"]]'
)
key_mm = page.query_selector(
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="mm"]]'
)
key_mm2 = page.query_selector(
'//div[@role="row" and .//div[@col-id="partyId"]/div/span[text()="mm2"]]'
)
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_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_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")
check_pnl_color_value(key_mm_realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_mm_unrealised_pnl, "rgb(1, 145, 75)", "4.00")
check_pnl_color_value(key_mm2_realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_mm2_unrealised_pnl, "rgb(0, 0, 0)", "0.00")
submit_order(vega, "Key 1", continuous_market, "SIDE_SELL", 2, 101.50000)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
wait_for_graphql_response(page, "EstimatePosition")
check_pnl_color_value(key_1_realised_pnl, "rgb(236, 0, 60)", "-8.00")
check_pnl_color_value(key_1_unrealised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_mm_realised_pnl, "rgb(1, 145, 75)", "8.00")
check_pnl_color_value(key_mm_unrealised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_mm2_realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(key_mm2_unrealised_pnl, "rgb(0, 0, 0)", "0.00")
page.get_by_role("link", name="Trading").click()
row = (
page.get_by_test_id("tab-positions")
.locator(".ag-center-cols-container .ag-row")
.nth(0)
)
realised_pnl = row.locator("[col-id='realisedPNL']")
unrealised_pnl = row.locator("[col-id='unrealisedPNL']")
# neutral trading realised
check_pnl_color_value(realised_pnl, "rgb(0, 0, 0)", "0.00")
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
# profit trading realised
page.get_by_test_id("manage-vega-wallet").click()
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(1).click(position={ "x": 0, "y": 0}, force=True)
check_pnl_color_value(realised_pnl, "rgb(1, 145, 75)", "8.00")
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")
# loss trading realised
page.locator('[role="menuitemradio"] >> .mr-2.uppercase').nth(0).click(position={ "x": 0, "y": 0}, force=True)
check_pnl_color_value(realised_pnl, "rgb(236, 0, 60)", "-8.00")
check_pnl_color_value(unrealised_pnl, "rgb(0, 0, 0)", "0.00")

View File

@ -0,0 +1,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")
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
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
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}"

View File

@ -0,0 +1,51 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from conftest import init_vega
from fixtures.market import setup_continuous_market
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')
# Verify headers
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(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%)")
# 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")]
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()

View File

@ -0,0 +1,29 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
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)
vega.submit_termination_and_settlement_data(
settlement_key="FJMKnwfZdd48C8NqvYrG",
settlement_price=110,
market_id=market_id,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
page.goto(f"/#/markets/{market_id}")
expect(page.locator(".ag-overlay-panel")).to_have_text("No positions")
page.get_by_test_id("open-transfer").click()
tab = page.get_by_test_id("tab-positions")
table = tab.locator(".ag-center-cols-container")
market = table.locator("[col-id='marketCode']")
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")

View File

@ -0,0 +1,61 @@
import pytest
from playwright.sync_api import expect, Page
from conftest import init_vega
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
yield vega
@pytest.mark.usefixtures("page", "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")
telemetry_switch.click()
expect(telemetry_switch).to_have_attribute("data-state", "checked")
page.reload()
page.get_by_test_id("Settings").click()
expect(telemetry_switch).to_have_attribute("data-state", "unchecked")
telemetry_switch.click()
expect(telemetry_switch).to_have_attribute("data-state", "checked")
page.reload()
page.get_by_test_id("Settings").click()
expect(telemetry_switch).to_have_attribute("data-state", "unchecked")
# Define a mapping of icon selectors to toast selectors
ICON_TO_TOAST = {
'aria-label="arrow-top-left icon"': 'class="group absolute z-20 top-0 left-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
'aria-label="arrow-up icon"': 'class="group absolute z-20 top-0 left-[50%] translate-x-[-50%] max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
'aria-label="arrow-top-right icon"': 'class="group absolute z-20 top-0 right-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
'aria-label="arrow-bottom-left icon"': 'class="group absolute z-20 bottom-0 left-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
'aria-label="arrow-down icon"': 'class="group absolute z-20 bottom-0 left-[50%] translate-x-[-50%] max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
'aria-label="arrow-bottom-right icon"': 'class="group absolute z-20 bottom-0 right-0 max-w-full max-h-full overflow-x-hidden overflow-y-auto p-4"',
}
@pytest.mark.usefixtures("page", "risk_accepted")
def test_toast_positions(page: Page):
page.goto("/")
page.get_by_test_id("Settings").click()
for icon_selector, toast_selector in ICON_TO_TOAST.items():
# Click the icon
page.click(f"[{icon_selector}]")
# Expect that the toast is displayed
expect(page.locator(f"[{toast_selector}]")).to_be_visible()
@pytest.mark.usefixtures("page", "risk_accepted")
def test_dark_mode(page: Page):
page.goto("/")
page.get_by_test_id("Settings").click()
expect(page.locator("html")).not_to_have_attribute("class", "dark")
page.locator("#switch-settings-theme-switch").click()
expect(page.locator("html")).to_have_attribute("class", "dark")

View File

@ -0,0 +1,47 @@
import pytest
from playwright.sync_api import Page, expect
from vega_sim.service import VegaService
from fixtures.market import setup_continuous_market, setup_simple_successor_market
@pytest.fixture
@pytest.mark.usefixtures("vega")
def successor_market(vega: VegaService):
parent_market_id = setup_continuous_market(vega)
tdai_id = vega.find_asset_id(symbol="tDAI")
successor_market_id = setup_simple_successor_market(
vega, parent_market_id, tdai_id, "successor_market"
)
vega.submit_termination_and_settlement_data(
settlement_key="FJMKnwfZdd48C8NqvYrG",
settlement_price=110,
market_id=parent_market_id,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
return successor_market_id
@pytest.mark.usefixtures("page", "risk_accepted")
def test_succession_line(page: Page, successor_market):
page.goto(f"/#/markets/{successor_market}")
page.get_by_test_id("Info").click()
page.get_by_text("Succession line").click()
expect(page.get_by_test_id("succession-line-item").first).to_contain_text(
"BTC:DAI_2023BTC:DAI_2023"
)
expect(
page.get_by_test_id("succession-line-item").first.get_by_role("link")
).to_be_attached
expect(page.get_by_test_id("succession-line-item").last).to_contain_text(
"successor_marketsuccessor_market"
)
expect(
page.get_by_test_id("succession-line-item").last.get_by_role("link")
).to_be_attached
expect(
page.get_by_test_id("succession-line-item").last.get_by_test_id("icon-bullet")
).to_be_visible

View File

@ -0,0 +1,106 @@
import pytest
import re
from playwright.sync_api import expect
from actions.vega import submit_order
from conftest import init_vega
import logging
logger = logging.getLogger()
@pytest.fixture(scope="module")
def vega():
with init_vega() as vega:
yield vega
# Could be turned into a helper function in the future.
def verify_data_grid(page, data_test_id, expected_pattern):
page.get_by_test_id(data_test_id).click()
# Required so that we can get liquidation price
if data_test_id == "Positions":
wait_for_graphql_response(page, "EstimatePosition")
expect(
page.locator(
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
)
).to_be_visible()
actual_text = page.locator(
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container'
).text_content()
lines = actual_text.strip().split("\n")
for expected, actual in zip(expected_pattern, lines):
# We are using regex so that we can run tests in different timezones.
if re.match(r"^\\d", expected): # check if it's a regex
if re.search(expected, actual):
logger.info(f"Matched: {expected} == {actual}")
else:
logger.info(f"Not Matched: {expected} != {actual}")
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
else: # it's not a regex, so we escape it
if re.search(re.escape(expected), actual):
logger.info(f"Matched: {expected} == {actual}")
else:
logger.info(f"Not Matched: {expected} != {actual}")
raise AssertionError(f"Pattern does not match: {expected} != {actual}")
# Required so that we can get liquidation price - Could also become a helper
def wait_for_graphql_response(page, query_name, timeout=5000):
response_data = {}
def handle_response(route, request):
if "graphql" in request.url:
response = request.response()
if response is not None:
json_response = response.json()
if json_response and "data" in json_response:
data = json_response["data"]
if query_name in data:
response_data["data"] = data
route.continue_()
return
route.continue_()
# Register the route handler
page.route("**", handle_response)
# Wait for the response data to be populated
page.wait_for_timeout(timeout)
# Unregister the route handler
page.unroute("**", handle_response)
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_limit_order_new_trade_top_of_list(continuous_market, vega, page):
submit_order(vega, "Key 1", continuous_market, "SIDE_BUY", 1, 110)
page.goto(f"/#/markets/{continuous_market}")
vega.forward("10s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
expected_trade = [
"103.50",
"1",
r"\d{1,2}/\d{1,2}/\d{4},\s*\d{1,2}:\d{2}:\d{2}\s*(?:AM|PM)" "107.50",
"1",
r"\d{1,2}/\d{1,2}/\d{4},\s*\d{1,2}:\d{2}:\d{2}\s*(?:AM|PM)",
]
# 6005-THIS-001
# 6005-THIS-002
# 6005-THIS-003
# 6005-THIS-004
# 6005-THIS-005
# 6005-THIS-006
verify_data_grid(page, "Trades", expected_trade)
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
def test_price_copied_to_deal_ticket(continuous_market, page):
page.goto(f"/#/markets/{continuous_market}")
page.get_by_test_id("Trades").click()
wait_for_graphql_response(page, "Trades")
page.locator("[col-id=price]").last.click()
# 6005-THIS-007
expect(page.get_by_test_id("order-price")).to_have_value("107.50000")

View File

@ -0,0 +1,214 @@
import pytest
from playwright.sync_api import expect, Page
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"
)
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}")
# sending order to be rejected, wait=False to avoid returning error from market-sim
vega.submit_order(
trading_key="Key 1",
market_id=opening_auction_market,
time_in_force="TIME_IN_FORCE_GTC",
order_type="TYPE_LIMIT",
side="SIDE_BUY",
volume=1,
price=10e15,
wait=False,
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
submit_multiple_orders(
vega,
"Key 1",
opening_auction_market,
"SIDE_BUY",
[[5, 110], [5, 105], [1, 50]],
)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
submit_multiple_orders(
vega,
"Key 1",
opening_auction_market,
"SIDE_SELL",
[[5, 90], [5, 95], [1, 150]],
)
vega.forward("60s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
# Positions
position = {
"market_code": "BTC:DAI_2023",
"settlement_asset": "tDAI",
"product_type": "Futr",
"size": "+2",
"notional": "220.00",
"average_entry_price": "110.00",
"mark_price": "110.00",
"margin": "93.52953",
"leverage": "1.0x",
"liquidation": "0.00",
"realised_pnl": "0.00",
"unrealised_pnl": "0.00",
}
page.goto(f"/#/markets/{opening_auction_market}")
# 7004-POSI-001
# 7004-POSI-002
primary_id = "stack-cell-primary"
secondary_id = "stack-cell-secondary"
tab = page.get_by_test_id("tab-positions")
table = tab.locator(".ag-center-cols-container")
market = table.locator("[col-id='marketCode']")
expect(market.get_by_test_id(primary_id)).to_have_text(position["market_code"])
expect(market.get_by_test_id(secondary_id)).to_have_text(
position["settlement_asset"] + position["product_type"]
)
size_and_notional = table.locator("[col-id='openVolume']")
expect(size_and_notional.get_by_test_id(primary_id)).to_have_text(position["size"])
expect(size_and_notional.get_by_test_id(secondary_id)).to_have_text(
position["notional"]
)
entry_and_mark = table.locator("[col-id='markPrice']")
expect(entry_and_mark.get_by_test_id(primary_id)).to_have_text(
position["average_entry_price"]
)
expect(entry_and_mark.get_by_test_id(secondary_id)).to_have_text(
position["mark_price"]
)
margin_and_leverage = table.locator("[col-id='margin']")
expect(margin_and_leverage.get_by_test_id(primary_id)).to_have_text(
position["margin"]
)
expect(margin_and_leverage.get_by_test_id(secondary_id)).to_have_text(
position["leverage"]
)
liquidation = table.locator("[col-id='liquidationPrice']")
expect(liquidation.get_by_test_id("liquidation-price")).to_have_text(
position["liquidation"]
)
realisedPNL = table.locator("[col-id='realisedPNL']")
expect(realisedPNL).to_have_text(position["realised_pnl"])
unrealisedPNL = table.locator("[col-id='unrealisedPNL']")
expect(unrealisedPNL).to_have_text(position["unrealised_pnl"])
# Open
page.get_by_test_id("Open").click()
rows = page.get_by_test_id("tab-open-orders").locator(row_locator).all()
expect(rows[0]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "-1" + "Limit" + "Active" + "150.00" + "GTC"
)
expect(rows[1]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "+1" + "Limit" + "Active" + "50.00" + "GTC"
)
expect(rows[2]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "+5" + "Limit" + "Active" + "105.00" + "GTC"
)
# Closed
page.get_by_test_id("Closed").click()
rows = page.get_by_test_id("tab-closed-orders").locator(row_locator).all()
expect(rows[0]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "-5" + "Limit" + "Filled" + "95.00" + "GTC"
)
expect(rows[1]).to_contain_text(
"BTC:DAI_2023Futr" + "5" + "-5" + "Limit" + "Filled" + "90.00" + "GTC"
)
expect(rows[2]).to_contain_text(
"BTC:DAI_2023Futr" + "5" + "+5" + "Limit" + "Filled" + "110.00" + "GTC"
)
# Rejected
page.get_by_test_id("Rejected").click()
expect(
page.get_by_test_id("tab-rejected-orders").locator(row_locator)
).to_contain_text(
"BTC:DAI_2023Futr"
+ "0"
+ "+1"
+ "Limit"
+ "Rejected: Margin check failed"
+ "10,000,000,000,000,000.00"
+ "GTC"
)
# All
page.get_by_test_id("All").click()
rows = page.get_by_test_id("tab-orders").locator(row_locator).all()
expect(rows[0]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "-1" + "Limit" + "Active" + "150.00" + "GTC"
)
expect(rows[1]).to_contain_text(
"BTC:DAI_2023Futr" + "5" + "-5" + "Limit" + "Filled" + "95.00" + "GTC"
)
expect(rows[2]).to_contain_text(
"BTC:DAI_2023Futr" + "5" + "-5" + "Limit" + "Filled" + "90.00" + "GTC"
)
expect(rows[3]).to_contain_text(
"BTC:DAI_2023Futr"
+ "0"
+ "+1"
+ "Limit"
+ "Rejected: Margin check failed"
+ "10,000,000,000,000,000.00"
+ "GTC"
)
expect(rows[4]).to_contain_text(
"BTC:DAI_2023Futr" + "0" + "+1" + "Limit" + "Active" + "50.00" + "GTC"
)
expect(rows[5]).to_contain_text(
"BTC:DAI_2023Futr" + "1" + "+5" + "Limit" + "Active" + "105.00" + "GTC"
)
expect(rows[6]).to_contain_text(
"BTC:DAI_2023Futr" + "5" + "+5" + "Limit" + "Filled" + "110.00" + "GTC"
)
# Stop Orders
page.get_by_test_id("Stop orders").click()
expect(page.get_by_test_id("tab-stop-orders")).to_be_visible()
expect(page.get_by_test_id("tab-stop-orders").locator(row_locator)).to_be_visible(
visible=False
)
# Fills
page.get_by_test_id("Fills").click()
rows = page.get_by_test_id("tab-fills").locator(row_locator).all()
expect(rows[0]).to_contain_text(
"BTC:DAI_2023Futr"
+ "-5"
+ "106.50 tDAI"
+ "532.50 tDAI"
+ "Taker"
+ "53.51625 tDAI"
)
expect(rows[1]).to_contain_text(
"BTC:DAI_2023Futr" + "+1" + "105.00 tDAI" + "105.00 tDAI" + "-" + "0.00 tDAI"
)
expect(rows[2]).to_contain_text(
"BTC:DAI_2023Futr" + "+5" + "105.00 tDAI" + "525.00 tDAI" + "-" + "0.00 tDAI"
)
# Collateral
page.get_by_test_id("Collateral").click()
expect(
page.get_by_test_id("tab-accounts").locator(".ag-floating-top-viewport .ag-row")
).to_contain_text("tDAI" + "43.94338" + "0.00%" + "999,904.04037" + "999,947.98375")

View File

@ -0,0 +1,139 @@
# import pytest
# import re
# from collections import namedtuple
# from playwright.sync_api import Page
# from vega_sim.service import VegaService
# from actions.vega import submit_order
# import logging
# logger = logging.getLogger()
# InfoItem = namedtuple('InfoItem', ['name', 'infoText'])
# @pytest.mark.skip("temporary skip")
# @pytest.mark.parametrize("vega", [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}")
# vega.forward("24h")
# vega.wait_for_total_catchup()
# submit_order(vega, "mm", continuous_market, "SIDE_SELL", 1, 101.50000)
# submit_order(vega, "mm2", continuous_market, "SIDE_SELL", 1, 101.50000)
# vega.forward("10s")
# vega.wait_for_total_catchup()
# page.click("button[aria-haspopup='menu']:has-text('Interval:')")
# page.click(f"div[role='menuitemradio']:text-is('15m')")
# page.wait_for_selector(".indicator-info-wrapper:visible")
# # Check chart views and select
# chart = "[aria-label$='chart icon']"
# valid_chart_views = ['Mountain', 'Candlestick', 'Line', 'OHLC']
# #6004-CHAR-002
# #6004-CHAR-003
# check_menu_items(page, chart, valid_chart_views, 'Candlestick')
# # Check study info
# study_info = [
# InfoItem("Eldar-ray","Eldar-ray: Bull -5.14286Bear -5.14286"),
# InfoItem("Force index", "Force index: -0.85714"),
# InfoItem("MACD", "MACD: S -0.09573D -0.38291MACD -0.47863"),
# InfoItem("RSI", "RSI: 0.00000"),
# InfoItem("Volume", "Volume: 1")
# ]
# """Preparation steps to check study info on the page."""
# element = page.locator(".plot-area-interaction").nth(1)
# element.hover()
# page.click(".pane__close-button-wrapper")
# info_items = page.query_selector_all(".plot-area")
# assert (len(info_items)) == 1
# #6004-CHAR-005
# #6004-CHAR-006
# #6004-CHAR-007
# #6004-CHAR-042
# #6004-CHAR-045
# #6004-CHAR-047
# #6004-CHAR-049
# #6004-CHAR-051
# page.mouse.wheel(0, 10)
# check_menu_item_checkbox(page, "Studies", study_info)
# page.get_by_text("Studies").click(force=True)
# # Check overlay info
# overlay_info = [
# InfoItem("Bollinger bands", "Bollinger: Upper 110.69473Lower 103.10527"),
# InfoItem("Envelope", "Envelope: Upper 111.65000Lower 91.35000"),
# InfoItem("EMA", "EMA: 106.30000"),
# InfoItem("Moving average", "Moving average: 106.90000"),
# InfoItem("Price monitoring bounds", "Price Monitoring Bounds 1: Min 83.11038Max 138.66685Reference 107.50000")
# ]
# #6004-CHAR-004
# #6004-CHAR-008
# #6004-CHAR-009
# #6004-CHAR-034
# #6004-CHAR-037
# #6004-CHAR-039
# #6004-CHAR-041
# check_menu_item_checkbox(page, "Overlays", overlay_info)
# # Check chart info
# # 6004-CHAR-010
# expected_date_regex = r"^\d{2}:\d{2} \d{2} [A-Za-z]{3} \d{4}$"
# expected_ohlc = "O 101.50000H 101.50000L 101.50000C 101.50000Change 6.00000(5.58%)"
# indicator_info_locator = page.locator(".indicator-info-wrapper").nth(0)
# texts = indicator_info_locator.all_text_contents()
# combined_text = ''.join(texts)
# actual_date = combined_text[:-67]
# actual_ohlc = combined_text[-67:]
# logger.info(actual_date)
# logger.info(actual_ohlc)
# assert re.match(expected_date_regex, actual_date)
# assert actual_ohlc == expected_ohlc
# # Check interval options and select '15m'
# interval = "button[aria-haspopup='menu']:has-text('Interval:')"
# valid_intervals = ['1m', '5m', '15m', '1H', '6H', '1D']
# #6004-CHAR-001
# page.click("button[aria-haspopup='menu']:has-text('Interval:')", force=True)
# check_menu_items(page, interval, valid_intervals, '1m')
# def check_menu_items(page, trigger_selector, valid_texts, click_item=None):
# page.click(trigger_selector, force=True)
# items = page.locator("div[role='menuitemradio']").all()
# assert len(items) == len(valid_texts), f"Expected {len(valid_texts)} items but found {len(items)} items."
# for i, el in enumerate(items):
# text = el.text_content().strip()
# assert text == valid_texts[i], f"Expected text '{valid_texts[i]}' but found '{text}'."
# if click_item:
# page.click(f"div[role='menuitemradio']:text-is('{click_item}')")
# page.click(trigger_selector)
# checked_item_text = page.text_content("div[role='menuitemradio'][data-state='checked']").strip()
# assert checked_item_text == click_item, f"Expected checked item text '{click_item}' but found '{checked_item_text}'."
# page.click(trigger_selector, force=True)
# def check_menu_item_checkbox(page, button_text, items):
# button_selector = f"button:has-text('{button_text}')"
# for item in items:
# page.click(button_selector)
# page.click(f"div[role='menuitemcheckbox']:has-text('{item.name}')")
# page.click(button_selector)
# checkbox_items = page.query_selector_all("div[role='menuitemcheckbox']")
# assert len(checkbox_items) == len(items), f"Expected {len(items)} checkboxes but found {len(checkbox_items)}."
# for i, el in enumerate(checkbox_items):
# text = el.text_content().strip()
# assert text == items[i].name, f"Expected checkbox text '{items[i].name}' but found '{text}'."
# for i, item in enumerate(items[0:]):
# info_locator = page.locator(".indicator-info-wrapper").nth(i+1)
# info_text = info_locator.text_content().strip()
# assert info_text == item.infoText, f"Expected info text '{item.infoText}' but found '{info_text}'."

View File

@ -0,0 +1,134 @@
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
import vega_sim.proto.vega as vega_protos
LIQ = WalletConfig("liq", "liq")
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")
def test_transfer_submit(continuous_market, vega: VegaService, page: Page):
# 1003-TRAN-001
# 1003-TRAN-006
# 1003-TRAN-007
# 1003-TRAN-008
# 1003-TRAN-009
# 1003-TRAN-010
# 1003-TRAN-023
page.goto('/#/portfolio')
expect(page.get_by_test_id('transfer-form')).to_be_visible
page.get_by_test_id('select-asset').click()
expect(page.get_by_test_id('rich-select-option')).to_have_count(1)
page.get_by_test_id('rich-select-option').click()
page.select_option('[data-testid=transfer-form] [name="toVegaKey"]', index=2)
page.select_option('[data-testid=transfer-form] [name="fromAccount"]', index=1)
expected_asset_text = re.compile(r"tDAI tDAI999,991.49731 tDAI.{6}….{4}")
actual_asset_text = page.get_by_test_id('select-asset').text_content().strip()
assert expected_asset_text.search(actual_asset_text), f"Expected pattern not found in {actual_asset_text}"
page.locator('[data-testid=transfer-form] input[name="amount"]').fill('1')
expect(page.locator('[data-testid=transfer-form] input[name="amount"]')).not_to_be_empty()
page.locator('[data-testid=transfer-form] [type="submit"]').click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmed View in block explorerTransferTo .{6}….{6}1\.00 tDAI")
actual_confirmation_text = page.get_by_test_id('toast-content').text_content()
assert expected_confirmation_text.search(actual_confirmation_text), f"Expected pattern not found in {actual_confirmation_text}"
@pytest.mark.usefixtures("page", "auth", "risk_accepted")
def test_transfer_vesting_below_minimum(continuous_market, vega: VegaService, page: Page):
vega.update_network_parameter(
"mm", parameter="transfer.minTransferQuantumMultiple", new_value="100000"
)
vega.wait_for_total_catchup()
create_and_faucet_wallet(vega=vega, wallet=PARTY_A, amount=1e3)
create_and_faucet_wallet(vega=vega, wallet=PARTY_B, amount=1e5)
create_and_faucet_wallet(vega=vega, wallet=PARTY_C, amount=1e5)
vega.wait_for_total_catchup()
asset_id = vega.find_asset_id(symbol="tDAI")
next_epoch(vega=vega)
vega.recurring_transfer(
from_key_name=PARTY_A.name,
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
to_account_type=vega_protos.vega.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
asset=asset_id,
asset_for_metric=asset_id,
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
amount=100,
factor=1.0,
)
# Generate trades for non-zero metrics
vega.submit_order(
trading_key=PARTY_B.name,
market_id=continuous_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_SELL",
price=0.30,
volume=100,
)
vega.submit_order(
trading_key=PARTY_C.name,
market_id=continuous_market,
order_type="TYPE_LIMIT",
time_in_force="TIME_IN_FORCE_GTC",
side="SIDE_BUY",
price=0.30,
volume=100,
)
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.get_by_test_id("manage-vega-wallet").click()
page.locator('[role="menuitemradio"]').nth(5).click()
page.reload()
page.get_by_test_id('select-asset').click()
page.get_by_test_id('rich-select-option').click()
option_value = page.locator('[data-testid="transfer-form"] [name="fromAccount"] option[value^="ACCOUNT_TYPE_VESTED_REWARDS"]').first.get_attribute("value")
page.select_option('[data-testid="transfer-form"] [name="fromAccount"]', option_value)
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")
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,
)
vega.forward("10s")
vega.wait_fn(10)
vega.wait_for_total_catchup()
page.get_by_text("Use max").first.click()
page.locator('[data-testid=transfer-form] [type="submit"]').click()
wait_for_toast_confirmation(page)
vega.forward("10s")
vega.wait_fn(1)
vega.wait_for_total_catchup()
expected_confirmation_text = re.compile(r"Transfer completeYour transaction has been confirmed View 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}"

View File

@ -1,13 +1,19 @@
#!/bin/bash -e
yarn --pure-lockfile
app=${1:-trading}
envCmd="envCmd="yarn -f ./apps/${app}/.env.${2:-mainnet}"
envCmd="yarn -f ./apps/${app}/.env.${2:-mainnet}"
yarn install
if [ "${app}" = "trading" ]; then
$envCmd yarn nx export trading
# Execute the command stored in envCmd and then run the nx export command
$envCmd && yarn nx export trading
DIST_LOCATION=dist/apps/trading/exported/
else
$envCmd yarn nx build ${app}
# Execute the command stored in envCmd and then run the nx build command
$envCmd && yarn nx build ${app}
DIST_LOCATION=dist/apps/${app}
fi
cp -r $DIST_LOCATION dist-result

View File

@ -13,7 +13,9 @@
"lint:all": "nx run-many --all --target=lint",
"e2e:all": "nx run-many --all --target=e2e",
"vegacapsule": "vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl",
"release": "git checkout develop ; git pull ; node scripts/make-release.js"
"release": "git checkout develop ; git pull ; node scripts/make-release.js",
"trading:test": "cd apps/trading/e2e && poetry run pytest -k",
"trading:test:all": "cd apps/trading/e2e && poetry run pytest -s --numprocesses 6 --dist loadfile"
},
"engines": {
"node": ">=20.9.0"