Compare commits

..
Author SHA1 Message Date
Matthew Russell a1e8fc878d chore: remove forwardRef as refs weren't being passed 2023-06-21 17:11:27 -07:00
613 changed files with 13662 additions and 16328 deletions
-1
View File
@@ -1 +0,0 @@
node_modules
+6 -11
View File
@@ -1,7 +1,7 @@
{ {
"root": true, "root": true,
"ignorePatterns": ["**/*"], "ignorePatterns": ["**/*"],
"plugins": ["@nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"], "plugins": ["@nrwl/nx", "eslint-plugin-unicorn", "jsx-a11y", "jest"],
"settings": { "settings": {
"jsx-a11y": { "jsx-a11y": {
"components": { "components": {
@@ -18,7 +18,7 @@
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"extends": ["plugin:jsx-a11y/strict"], "extends": ["plugin:jsx-a11y/strict"],
"rules": { "rules": {
"@nx/enforce-module-boundaries": [ "@nrwl/nx/enforce-module-boundaries": [
"error", "error",
{ {
"enforceBuildableLibDependency": true, "enforceBuildableLibDependency": true,
@@ -56,7 +56,7 @@
}, },
{ {
"files": ["*.ts", "*.tsx"], "files": ["*.ts", "*.tsx"],
"extends": ["plugin:@nx/typescript"], "extends": ["plugin:@nrwl/nx/typescript"],
"rules": { "rules": {
"@typescript-eslint/ban-ts-comment": [ "@typescript-eslint/ban-ts-comment": [
"error", "error",
@@ -80,19 +80,14 @@
}, },
{ {
"files": ["*.spec.ts", "*.spec.tsx"], "files": ["*.spec.ts", "*.spec.tsx"],
"extends": ["plugin:@nx/typescript", "plugin:jest/recommended"], "extends": ["plugin:@nrwl/nx/typescript", "plugin:jest/recommended"],
"rules": { "rules": {
"jest/consistent-test-it": [ "jest/consistent-test-it": ["error", { "fn": "it" }]
"error",
{
"fn": "it"
}
]
} }
}, },
{ {
"files": ["*.js", "*.jsx"], "files": ["*.js", "*.jsx"],
"extends": ["plugin:@nx/javascript"], "extends": ["plugin:@nrwl/nx/javascript"],
"rules": {} "rules": {}
} }
] ]
-28
View File
@@ -1,28 +0,0 @@
---
name: Feature Epic
about: A template to capture and scope user requirements, high level process, and basic mockups for an upcoming feature as part of the initial core spec review process.
title: 'FEATURE EPIC: '
labels: feature-epic
---
## Core Feature
<Name>
## Tasks
- [ ] Define high level requirements
- [ ] Create basic mockups
- [ ] Update "API Requirements" in core spec
- [ ] Update "User-Interface Spec" in relevant front end repo
- [ ] Create detailed user stories using normal template
## High Level Requirements
## Basic Mockups
## Link to API Requirements in Core spec
## Link to User Interface Specs
## Linked User Stories
+1 -1
View File
@@ -1,6 +1,6 @@
# Related issues 🔗 # Related issues 🔗
Issue: #[Issue number here] Closes #[Issue number here]
# Description # Description
@@ -7,7 +7,7 @@ on:
jobs: jobs:
after-release: after-release:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
timeout-minutes: 45 timeout-minutes: 30
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -30,20 +30,18 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Wait for publish to complete
uses: lewagon/wait-on-check-action@v1.3.1
with:
ref: ${{ github.event.release.tag_name }}
check-name: '(CD) publish dist / trading'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
- name: resolve ipfs hashes for release - name: resolve ipfs hashes for release
run: | run: |
echo "Name: ${{ github.event.release.name }}" echo "Name: ${{ github.event.release.name }}"
echo "Description: ${{ github.event.release.body }}" echo "Description: ${{ github.event.release.body }}"
echo "Tag: ${{ github.event.release.tag_name }}" echo "Tag: ${{ github.event.release.tag_name }}"
docker run --rm vegaprotocol/trading:mainnet cat /ipfs-hash > ipfs-hash commit="$(git rev-list -n 1 ${{ github.event.release.tag_name }})"
echo "Commit: $commit"
until docker pull vegaprotocol/trading:$commit; do
echo "Image not pushed yet, waiting 60 seconds"
sleep 60
done
docker run --rm vegaprotocol/trading:$commit cat /ipfs-hash > ipfs-hash
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
tar -xzf kubo.tgz tar -xzf kubo.tgz
export PATH="$PATH:$PWD/kubo" export PATH="$PATH:$PWD/kubo"
+1 -1
View File
@@ -6,7 +6,7 @@ name: 'Add Issues To Project Board'
types: types:
- opened - opened
env: env:
GH_TOKEN: ${{ secrets.PROJECT_MANAGE_ACTION }} GH_TOKEN: ${{ secrets.GH_NEW_CARD_TO_PROJECT }}
PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }} PROJECT_ID: ${{ secrets.FRONT_END_PROJECT_ID }}
ISSUE_ID: ${{ github.event.issue.node_id }} ISSUE_ID: ${{ github.event.issue.node_id }}
USER: ${{ github.actor }} USER: ${{ github.actor }}
+98 -48
View File
@@ -5,6 +5,7 @@ on:
branches: branches:
- release/* - release/*
- develop - develop
- main
pull_request: pull_request:
types: types:
- opened - opened
@@ -19,8 +20,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Cache node modules - name: Cache node modules
id: cache id: cache
@@ -61,7 +60,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
@@ -81,36 +79,97 @@ jobs:
with: with:
main-branch-name: develop main-branch-name: develop
- name: Check formatting
run: yarn nx format:check
- name: Lint affected
run: yarn nx affected:lint --max-warnings=0
- name: Build affected spec
run: yarn nx affected --target=build-spec
- name: Test affected
run: yarn nx affected:test
- name: Build affected
run: yarn nx affected:build || (yarn install && yarn nx affected:build)
# See affected apps # See affected apps
- name: See affected apps - name: See affected apps
run: | run: |
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)"
branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )" branch_slug="$(echo '${{ github.head_ref || github.ref_name }}' | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | cut -c 1-50 )"
python3 tools/ci/check-affected.py --github-ref="${{ github.ref }}" --branch-slug="$branch_slug" --event-name="${{ github.event_name }}"
- name: Verify script result echo ">>>> debug"
run: | echo "NX_BASE: ${{ env.NX_BASE }}"
echo "Check outputs from script" echo "NX_HEAD: ${{ env.NX_HEAD }}"
echo "projects: ${{ env.PROJECTS }}" echo "Affected: ${affected}"
echo "projects-e2e: ${{ env.PROJECTS_E2E }}" echo "Branch slug: ${branch_slug}"
echo "preview_governance: ${{ env.PREVIEW_GOVERNANCE }}" echo ">>>> eof debug"
echo "preview_trading: ${{ env.PREVIEW_TRADING }}"
echo "preview_explorer: ${{ env.PREVIEW_EXPLORER }}"
echo "preview_tools: ${{ env.PREVIEW_TOOLS }}"
# - name: Check formatting projects_e2e=""
# run: yarn nx format:check preview_governance="not deployed"
preview_trading="not deployed"
preview_explorer="not deployed"
preview_tools="not deployed"
if echo "$affected" | grep -q governance; then
echo "Governance is affected"
projects_e2e+='"governance-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
fi
if echo "$affected" | grep -q trading; then
echo "Trading is affected"
projects_e2e+='"trading-e2e" '
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
fi
if echo "$affected" | grep -q explorer; then
echo "Explorer is affected"
projects_e2e+='"explorer-e2e" '
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
if [[ -z "$projects_e2e" ]]; then
projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '
preview_governance=$(printf "https://%s.%s.vega.rocks" "governance" "$branch_slug")
preview_trading=$(printf "https://%s.%s.vega.rocks" "trading" "$branch_slug")
preview_explorer=$(printf "https://%s.%s.vega.rocks" "explorer" "$branch_slug")
fi
projects="$(echo $projects_e2e | sed 's|-e2e||g')"
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
if echo "$affected" | grep -q multisig-signer; then
echo "Tools are affected"
# tools are only applicable to check previews or deploy from develop to mainnet
echo "Deploying tools on preview"
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
projects+=' "multisig-signer" '
fi
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
if echo "$affected" | grep -q multisig-signer; then
echo "Tools are affected"
# tools are only applicable to check previews or deploy from develop to mainnet
echo "Deploying tools on s3"
projects+=' "multisig-signer" '
fi
if echo "$affected" | grep -q static; then
echo "static is affected"
echo "Deploying static on s3"
projects+=' "static" '
fi
if echo "$affected" | grep -q ui-toolkit; then
echo "ui-toolkit is affected"
echo "Deploying ui-toolkit on s3"
projects+=' "ui-toolkit" '
fi
fi
# - name: Lint affected projects_e2e=${projects_e2e%?}
# run: yarn nx affected:lint --max-warnings=0 projects_e2e=[${projects_e2e// /,}]
projects=[${projects// /,}]
# - name: Build affected spec echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
# run: yarn nx affected --target=build-spec echo PROJECTS=$projects >> $GITHUB_ENV
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
# - name: Test affected echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
# run: yarn nx affected:test echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
echo PREVIEW_TOOLS=$preview_tools >> $GITHUB_ENV
# - name: Build affected
# run: yarn nx affected:build || (yarn install && yarn nx affected:build)
outputs: outputs:
projects: ${{ env.PROJECTS }} projects: ${{ env.PROJECTS }}
@@ -120,29 +179,20 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }} preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }} preview_tools: ${{ env.PREVIEW_TOOLS }}
console-e2e:
needs: lint-test-build
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: ${{ contains(fromJSON(needs.lint-test-build.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
cypress: cypress:
needs: lint-test-build needs: lint-test-build
name: '(CI) cypress' name: '(CI) cypress'
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }} if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
uses: ./.github/workflows/cypress-run.yml uses: ./.github/workflows/cypress-run.yml
secrets: inherit secrets: inherit
with: with:
projects: ${{ needs.lint-test-build.outputs.projects-e2e }} projects: ${{ needs.lint-test-build.outputs.projects-e2e }}
tags: '@smoke' tags: '@smoke @regression'
publish-dist: publish-dist:
needs: lint-test-build needs: lint-test-build
name: '(CD) publish dist' name: '(CD) publish dist'
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo') || github.event_name == 'push' }} if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
uses: ./.github/workflows/publish-dist.yml uses: ./.github/workflows/publish-dist.yml
secrets: inherit secrets: inherit
with: with:
@@ -153,7 +203,7 @@ jobs:
needs: needs:
- publish-dist - publish-dist
- lint-test-build - lint-test-build
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'vegaprotocol/frontend-monorepo' }} if: ${{ github.event_name == 'pull_request' }}
timeout-minutes: 60 timeout-minutes: 60
name: '(CD) comment preview links' name: '(CD) comment preview links'
steps: steps:
@@ -169,26 +219,26 @@ jobs:
# https://stackoverflow.com/questions/3183444/check-for-valid-link-url # https://stackoverflow.com/questions/3183444/check-for-valid-link-url
regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]' regex='(https?|ftp|file)://[-[:alnum:]\+&@#/%?=~_|!:,.;]*[-[:alnum:]\+&@#/%=~_|]'
if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then if [[ "${{ needs.lint-test-build.outputs.preview_governance }}" =~ $regex ]]; then
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do until curl -L --fail "${{ needs.lint-test-build.outputs.preview_governance }}"; do
echo "waiting for governance preview: ${{ needs.lint-test-build.outputs.preview_governance }}" echo "waiting for governance preview"
sleep 5 sleep 5
done done
fi fi
if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then if [[ "${{ needs.lint-test-build.outputs.preview_explorer }}" =~ $regex ]]; then
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do until curl -L --fail "${{ needs.lint-test-build.outputs.preview_explorer }}"; do
echo "waiting for explorer preview: ${{ needs.lint-test-build.outputs.preview_explorer }}" echo "waiting for explorer preview"
sleep 5 sleep 5
done done
fi fi
if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then if [[ "${{ needs.lint-test-build.outputs.preview_trading }}" =~ $regex ]]; then
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do until curl -L --fail "${{ needs.lint-test-build.outputs.preview_trading }}"; do
echo "waiting for trading preview: ${{ needs.lint-test-build.outputs.preview_trading }}" echo "waiting for trading preview"
sleep 5 sleep 5
done done
fi fi
if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then if [[ "${{ needs.lint-test-build.outputs.preview_tools }}" =~ $regex ]]; then
until curl --insecure --location --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do until curl -L --fail "${{ needs.lint-test-build.outputs.preview_tools }}"; do
echo "waiting for tools preview: ${{ needs.lint-test-build.outputs.preview_tools }}" echo "waiting for tools preview"
sleep 5 sleep 5
done done
fi fi
@@ -199,7 +249,7 @@ jobs:
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body: | body: |
Previews Previews:
* governance: ${{ needs.lint-test-build.outputs.preview_governance }} * governance: ${{ needs.lint-test-build.outputs.preview_governance }}
* explorer: ${{ needs.lint-test-build.outputs.preview_explorer }} * explorer: ${{ needs.lint-test-build.outputs.preview_explorer }}
* trading: ${{ needs.lint-test-build.outputs.preview_trading }} * trading: ${{ needs.lint-test-build.outputs.preview_trading }}
-142
View File
@@ -1,142 +0,0 @@
name: (CI) Console tests
on:
workflow_call:
inputs:
github-sha:
required: true
type: string
jobs:
run-tests:
name: run-tests
runs-on: 8-cores
timeout-minutes: 20
steps:
#----------------------------------------------
# check-out frontend-monorepo
#----------------------------------------------
- name: Checkout console test repo
uses: actions/checkout@v3
with:
ref: ${{ inputs.github-sha }}
#----------------------------------------------
# cache node modules
#----------------------------------------------
- name: Cache node modules
id: cache
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}
# comment out "restore-keys" if you need to rebuild yarn from 0
restore-keys: |
${{ runner.os }}-cache-node-modules-
#----------------------------------------------
# setup node
#----------------------------------------------
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
# https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
cache: yarn
#----------------------------------------------
# install deps if cache missing
#----------------------------------------------
- name: yarn install
if: steps.cache.outputs.cache-hit != 'true'
run: yarn install --pure-lockfile
#----------------------------------------------
# build trading
#----------------------------------------------
- name: Build affected spec
run: |
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
#----------------------------------------------
# run trading server
#----------------------------------------------
- name: Run trading server
run: |
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
sleep 5
docker ps
#----------------------------------------------
# check if container persists between runs
#----------------------------------------------
- name: Check server
run: |
docker ps
#----------------------------------------------
# check-out tests repo
#----------------------------------------------
- name: Checkout console test repo
uses: actions/checkout@v3
with:
repository: vegaprotocol/console-test
path: './console-test'
#----------------------------------------------
# set-up python
#----------------------------------------------
- name: Set up python
id: setup-python
uses: actions/setup-python@v4
with:
python-version: '3.10.11'
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: console-test/.venv
#----------------------------------------------
# load cached venv if cache exists
#----------------------------------------------
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: console-test/.venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
#----------------------------------------------
# install dependencies if cache does not exist
#----------------------------------------------
- name: Install dependencies
working-directory: ./console-test
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
#----------------------------------------------
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
working-directory: ./console-test
run: poetry run python -m vega_sim.tools.load_binaries --force
#----------------------------------------------
# install playwright
#----------------------------------------------
- name: install playwright
run: poetry run playwright install
working-directory: ./console-test
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
working-directory: ./console-test
run: poetry run pytest -v -s --numprocesses auto --dist loadfile --durations=20
- name: Check files
run: |
ls -al .
ls -al console-test
#----------------------------------------------
# upload traces
#----------------------------------------------
- name: Upload Playwright Trace
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-trace
path: ./traces/
retention-days: 15
+1 -2
View File
@@ -20,7 +20,7 @@ jobs:
project: ${{ fromJSON(inputs.projects) }} project: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.project }} name: ${{ matrix.project }}
runs-on: self-hosted-runner runs-on: self-hosted-runner
timeout-minutes: 120 timeout-minutes: 100
steps: steps:
# Checks if skip cache was requested # Checks if skip cache was requested
- name: Set skip-nx-cache flag - name: Set skip-nx-cache flag
@@ -33,7 +33,6 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
path: './frontend-monorepo' path: './frontend-monorepo'
ref: ${{ github.event.pull_request.head.sha || github.sha }}
# Restore node_modules from cache if possible # Restore node_modules from cache if possible
- name: Restore node_modules from cache - name: Restore node_modules from cache
-2
View File
@@ -11,8 +11,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
+65 -87
View File
@@ -19,47 +19,6 @@ jobs:
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Init variables
run: |
echo IS_PR=false >> $GITHUB_ENV
echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
echo IS_S3_RELEASE=false >> $GITHUB_ENV
echo IS_DEV_IMAGE=false >> $GITHUB_ENV
- name: Is dev image
if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
run: |
echo IS_DEV_IMAGE=true >> $GITHUB_ENV
- name: Is PR
if: ${{ github.event_name == 'pull_request' }}
run: |
echo IS_PR=true >> $GITHUB_ENV
- name: Is mainnet release
if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
run: |
echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV
- name: Is testnet release
if: ${{ contains(github.ref, 'release/testnet') }}
run: |
echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV
- name: Is IPFS Release
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
run: |
echo IS_IPFS_RELEASE=true >> $GITHUB_ENV
- name: Is S3 Release
if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
run: |
echo IS_S3_RELEASE=true >> $GITHUB_ENV
- name: Set up QEMU - name: Set up QEMU
id: quemu id: quemu
@@ -72,7 +31,7 @@ jobs:
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry (ghcr) - name: Log in to the Container registry (ghcr)
if: ${{ env.IS_PR == 'true' }} if: ${{ github.event_name == 'pull_request' }}
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
@@ -81,8 +40,9 @@ jobs:
- name: Log in to the Container registry (docker hub) - name: Log in to the Container registry (docker hub)
uses: docker/login-action@v2 uses: docker/login-action@v2
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }} if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
with: with:
# registry: registry.hub.docker.com
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -103,33 +63,67 @@ jobs:
- name: Define dist variables - name: Define dist variables
if: ${{ github.event_name == 'push' }} if: ${{ github.event_name == 'push' }}
run: | run: |
python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}" envName=''
domain="vega.rocks"
bucketName=''
- name: Verify script result if [[ "${{ github.ref }}" =~ .*release/.* ]]; then
if: ${{ github.event_name == 'push' }} envName="$(echo ${{ github.ref }} | rev | cut -d '/' -f 1 | rev)"
run: | elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
echo "BUCKET_NAME=${{ env.BUCKET_NAME }}" envName="stagnet1"
echo "ENV_NAME=${{ env.ENV_NAME }}" if [[ "${{ matrix.app }}" = "multisig-signer" ]]; then
envName="mainnet"
bucketName="tools.vega.xyz"
fi
if [[ "${{ matrix.app }}" = "static" ]]; then
envName="mainnet"
bucketName="static.vega.xyz"
fi
if [[ "${{ matrix.app }}" = "ui-toolkit" ]]; then
envName="mainnet"
bucketName="ui.vega.rocks"
fi
elif [[ "${{ github.ref }}" =~ .*main$ ]]; then
envName="mainnet"
fi
if [[ "${envName}" = "mainnet" ]]; then
domain="vega.xyz"
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${domain}"
fi
elif [[ "${envName}" = "testnet" ]]; then
domain="fairground.wtf"
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${domain}"
fi
fi
if [[ -z "${bucketName}" ]]; then
bucketName="${{ matrix.app }}.${envName}.${domain}"
fi
echo "bucket name: ${bucketName}"
echo "env name: ${envName}"
echo BUCKET_NAME=${bucketName} >> $GITHUB_ENV
echo ENV_NAME=${envName} >> $GITHUB_ENV
- name: Build local dist - name: Build local dist
run: | run: |
envCmd="" flags=""
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}" flags="--env=${{ env.ENV_NAME }}"
fi fi
if [ "${{ matrix.app }}" = "trading" ]; then if [ "${{ matrix.app }}" = "trading" ]; then
$envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading) yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
DIST_LOCATION=dist/apps/trading/exported DIST_LOCATION=dist/apps/trading/exported
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
NODE_ENV=production yarn nx run ui-toolkit:build-storybook NODE_ENV=production yarn nx run ui-toolkit:build-storybook
DIST_LOCATION=dist/storybook/ui-toolkit DIST_LOCATION=dist/storybook/ui-toolkit
elif [ "${{ matrix.app }}" = "static" ]; then
yarn nx build static || (yarn install && yarn nx build static)
else else
$envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }}) yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
fi
if [[ -z "$DIST_LOCATION" ]]; then
DIST_LOCATION=dist/apps/${{ matrix.app }} DIST_LOCATION=dist/apps/${{ matrix.app }}
fi fi
mv $DIST_LOCATION dist-result mv $DIST_LOCATION dist-result
@@ -149,7 +143,7 @@ jobs:
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest - name: Image digest
if: ${{ env.IS_PR == 'true' }} if: ${{ github.event_name == 'pull_request' }}
run: echo ${{ steps.docker_build.outputs.digest }} run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image - name: Sanity check docker image
@@ -164,7 +158,7 @@ jobs:
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
continue-on-error: true continue-on-error: true
id: ghcr-push id: ghcr-push
if: ${{ env.IS_PR == 'true' }} if: ${{ github.event_name == 'pull_request' }}
with: with:
context: . context: .
file: docker/node-outside-docker.Dockerfile file: docker/node-outside-docker.Dockerfile
@@ -179,7 +173,7 @@ jobs:
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
continue-on-error: true continue-on-error: true
id: dockerhub-push id: dockerhub-push
if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }} if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
with: with:
context: . context: .
file: docker/node-outside-docker.Dockerfile file: docker/node-outside-docker.Dockerfile
@@ -189,7 +183,7 @@ jobs:
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
vegaprotocol/${{ matrix.app }}:${{ github.sha }} vegaprotocol/${{ matrix.app }}:${{ github.sha }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }} vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
- name: Publish dist as docker image (ghcr - retry) - name: Publish dist as docker image (ghcr - retry)
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
@@ -216,13 +210,13 @@ jobs:
ENV_NAME=${{ env.ENV_NAME }} ENV_NAME=${{ env.ENV_NAME }}
tags: | tags: |
vegaprotocol/${{ matrix.app }}:${{ github.sha }} vegaprotocol/${{ matrix.app }}:${{ github.sha }}
vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }} vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
# bucket creation in github.com/vegaprotocol/terraform//frontend # bucket creation in github.com/vegaprotocol/terraform//frontend
- name: Publish dist to s3 - name: Publish dist to s3
uses: jakejarvis/s3-sync-action@master uses: jakejarvis/s3-sync-action@master
# s3 releases are not happening for trading on mainnet - it's IPFS # s3 releases are not happening for trading on mainnet - it's IPFS
if: ${{ env.IS_S3_RELEASE == 'true' }} if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
with: with:
args: --acl private --follow-symlinks --delete args: --acl private --follow-symlinks --delete
env: env:
@@ -232,34 +226,18 @@ jobs:
AWS_REGION: 'eu-west-1' AWS_REGION: 'eu-west-1'
SOURCE_DIR: 'dist-result' SOURCE_DIR: 'dist-result'
- name: Install aws CLI
if: ${{ env.IS_S3_RELEASE == 'true' }}
uses: unfor19/install-aws-cli-action@master
- name: Perform cache invalidation
if: ${{ env.IS_S3_RELEASE == 'true' }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: 'eu-west-1'
run: |
echo "Looking for distribution for bucket: ${{ env.BUCKET_NAME }}"
id=$(aws cloudfront list-distributions | jq -Mrc '.DistributionList.Items | .[] | select(.DefaultCacheBehavior.TargetOriginId == "${{ env.BUCKET_NAME }}") | .Id')
echo "Found id is: ${id}"
aws cloudfront create-invalidation --distribution-id $id --paths "/*"
- name: Add preview label - name: Add preview label
uses: actions-ecosystem/action-add-labels@v1 uses: actions-ecosystem/action-add-labels@v1
if: ${{ env.IS_PR == 'true' }} if: ${{ github.event_name == 'pull_request' }}
with: with:
labels: ${{ matrix.app }}-preview labels: ${{ matrix.app }}-preview
number: ${{ github.event.number }} number: ${{ github.event.number }}
- name: Trigger fleek deployment - name: Trigger fleek deployment
# release to ipfs happens only on mainnet (represented by main branch) for trading # release to ipfs happens only on mainnet (represented by main branch) for trading
if: ${{ env.IS_IPFS_RELEASE == 'true' }} if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
run: | run: |
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then if echo ${{ github.ref }} | grep -q main; then
# display info about app # display info about app
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \ curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
@@ -272,7 +250,7 @@ jobs:
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \ -d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
https://api.fleek.co/graphql https://api.fleek.co/graphql
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then elif echo ${{ github.ref }} | grep -q release/testnet; then
# display info about app # display info about app
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \ curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
@@ -287,7 +265,7 @@ jobs:
fi fi
- name: Check out ipfs-redirect - name: Check out ipfs-redirect
if: ${{ env.IS_IPFS_RELEASE == 'true' }} if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: 'vegaprotocol/ipfs-redirect' repository: 'vegaprotocol/ipfs-redirect'
@@ -296,7 +274,7 @@ jobs:
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
- name: Update interstitial page to point to the new console - name: Update interstitial page to point to the new console
if: ${{ env.IS_IPFS_RELEASE == 'true' }} if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
env: env:
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
run: | run: |
@@ -318,11 +296,11 @@ jobs:
git config --global user.name "vega-ci-bot" git config --global user.name "vega-ci-bot"
# update CID files # update CID files
if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then if echo ${{ github.ref }} | grep -q main; then
echo $new_hash > cidv0-mainnet.txt echo $new_hash > cidv0-mainnet.txt
echo $new_cid > cidv1-mainnet.txt echo $new_cid > cidv1-mainnet.txt
git add cidv0-mainnet.txt cidv1-mainnet.txt git add cidv0-mainnet.txt cidv1-mainnet.txt
elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then elif echo ${{ github.ref }} | grep -q release/testnet; then
echo $new_hash > cidv0-fairground.txt echo $new_hash > cidv0-fairground.txt
echo $new_cid > cidv1-fairground.txt echo $new_cid > cidv1-fairground.txt
git add cidv0-fairground.txt cidv1-fairground.txt git add cidv0-fairground.txt cidv1-fairground.txt
-1
View File
@@ -15,7 +15,6 @@ on:
- types - types
- utils - utils
- i18n - i18n
- wallet
jobs: jobs:
publish: publish:
+2 -2
View File
@@ -2,7 +2,7 @@
. "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/husky.sh"
# Lint commit messages to ensure they follow conventional commit standards # Lint commit messages to ensure they follow conventional commit standards
# yarn commitlint --edit "${1}" yarn commitlint --edit "${1}"
# Lint all staged files # Lint all staged files
# yarn lint-staged yarn lint-staged
-5
View File
@@ -1,5 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# Lint all staged files
# yarn lint-staged
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# Lint all staged files
# yarn nx format:check
# Test all projects with changes
# yarn nx affected -t test --exclude trading
+29
View File
@@ -0,0 +1,29 @@
module.exports = {
stories: [],
addons: [
'@storybook/addon-actions',
'@storybook/addon-viewport',
{
name: '@storybook/addon-docs',
options: {
configureJSX: true,
babelOptions: {},
sourceLoaderOptions: null,
transcludeMarkdown: true,
},
},
'@storybook/addon-controls',
'@storybook/addon-backgrounds',
'@storybook/addon-toolbars',
'@storybook/addon-measure',
'@storybook/addon-outline',
'@storybook/addon-a11y',
],
// uncomment the property below if you want to apply some webpack config globally
// webpackFinal: async (config, { configType }) => {
// // Make whatever fine-grained changes you need that should apply to all storybook configs
// // Return the altered config
// return config;
// },
};
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "../tsconfig.base.json",
"exclude": [
"../**/*.spec.js",
"../**/*.test.js",
"../**/*.spec.ts",
"../**/*.test.ts",
"../**/*.spec.tsx",
"../**/*.test.tsx",
"../**/*.spec.jsx",
"../**/*.test.jsx"
],
"include": ["../**/*"]
}
+3 -4
View File
@@ -1,11 +1,10 @@
{ {
"name": "explorer-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json", "$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/explorer-e2e/src", "sourceRoot": "apps/explorer-e2e/src",
"projectType": "application", "projectType": "application",
"targets": { "targets": {
"e2e": { "e2e": {
"executor": "@nx/cypress:cypress", "executor": "@nrwl/cypress:cypress",
"options": { "options": {
"cypressConfig": "apps/explorer-e2e/cypress.config.js", "cypressConfig": "apps/explorer-e2e/cypress.config.js",
"devServerTarget": "explorer:serve" "devServerTarget": "explorer:serve"
@@ -17,14 +16,14 @@
} }
}, },
"lint": { "lint": {
"executor": "@nx/linter:eslint", "executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"], "outputs": ["{options.outputFile}"],
"options": { "options": {
"lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"] "lintFilePatterns": ["apps/explorer-e2e/**/*.{js,ts}"]
} }
}, },
"build": { "build": {
"executor": "nx:run-commands", "executor": "@nrwl/workspace:run-commands",
"outputs": [], "outputs": [],
"options": { "options": {
"command": "yarn tsc --project ./apps/explorer-e2e/" "command": "yarn tsc --project ./apps/explorer-e2e/"
@@ -31,7 +31,7 @@ context('Asset page', { tags: '@regression' }, () => {
}); });
}); });
it.skip('should open details page when clicked on "View details"', () => { it('should open details page when clicked on "View details"', () => {
cy.getAssets().then((assets) => { cy.getAssets().then((assets) => {
assets.forEach((asset) => { assets.forEach((asset) => {
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`) cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
@@ -169,6 +169,7 @@ context.skip('Parties page', { tags: '@regression' }, function () {
const jsonFields = '.hljs'; const jsonFields = '.hljs';
const sideMenuBackground = '.absolute'; const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground) cy.get(sideMenuBackground)
.should('have.css', 'background-color') .should('have.css', 'background-color')
.then((background_color) => { .then((background_color) => {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"presets": [ "presets": [
[ [
"@nx/react/babel", "@nrwl/react/babel",
{ {
"runtime": "automatic" "runtime": "automatic"
} }
+3 -3
View File
@@ -1,14 +1,14 @@
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.rocks NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1 NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_WALLET_URL=http://localhost:1789
NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.rocks/rest NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks NX_VEGA_GOVERNANCE_URL=https://governance.stagnet1.vega.rocks
+1 -1
View File
@@ -1,5 +1,5 @@
# App configuration variables # App configuration variables
NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/ NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
NX_VEGA_ENV=DEVNET NX_VEGA_ENV=DEVNET
-13
View File
@@ -1,13 +0,0 @@
# App configuration variables
NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/mainnet-mirror/vegawallet-mainnet-mirror.toml
NX_VEGA_URL=https://api.mainnet-mirror.vega.rocks/graphql
NX_VEGA_ENV=MAINNET-MIRROR
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.rocks/rest
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/
NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"extends": ["plugin:@nx/react", "../../.eslintrc.json"], "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__"], "ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+1 -2
View File
@@ -32,7 +32,6 @@ yarn nx serve explorer
Example configurations are provided here: Example configurations are provided here:
- [Mainnet](./.env.mainnet) - [Mainnet](./.env.mainnet)
- [Mainnet-mirror](./.env.mainnet-mirror)
- [Devnet](./.env.devnet) - [Devnet](./.env.devnet)
- [Capsule](./.env.capsule) - [Capsule](./.env.capsule)
- [Testnet](./.env.testnet) - [Testnet](./.env.testnet)
@@ -40,7 +39,7 @@ Example configurations are provided here:
For convenience, you can boot the app injecting one of the configurations above by running: For convenience, you can boot the app injecting one of the configurations above by running:
```bash ```bash
yarn env-cmd -f .\apps\explorer\.env.{env} yarn nx run explorer:serve # e.g. stagnet1 yarn nx run explorer:serve --env={env} # e.g. stagnet1
``` ```
There are a few different configuration options offered for this app: There are a few different configuration options offered for this app:
+2 -2
View File
@@ -4,8 +4,8 @@ export default {
displayName: 'explorer', displayName: 'explorer',
preset: '../../jest.preset.js', preset: '../../jest.preset.js',
transform: { transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], '^.+\\.[tj]sx?$': 'babel-jest',
}, },
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/explorer', coverageDirectory: '../../coverage/apps/explorer',
+9 -16
View File
@@ -1,11 +1,10 @@
{ {
"name": "explorer",
"$schema": "../../node_modules/nx/schemas/project-schema.json", "$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/explorer/src", "sourceRoot": "apps/explorer/src",
"projectType": "application", "projectType": "application",
"targets": { "targets": {
"build": { "build": {
"executor": "@nx/webpack:webpack", "executor": "./tools/executors/webpack:build",
"outputs": ["{options.outputPath}"], "outputs": ["{options.outputPath}"],
"defaultConfiguration": "production", "defaultConfiguration": "production",
"options": { "options": {
@@ -39,7 +38,7 @@
} }
}, },
"serve": { "serve": {
"executor": "@nx/webpack:dev-server", "executor": "./tools/executors/webpack:serve",
"options": { "options": {
"port": 3000, "port": 3000,
"buildTarget": "explorer:build:development", "buildTarget": "explorer:build:development",
@@ -53,36 +52,30 @@
} }
}, },
"lint": { "lint": {
"executor": "@nx/linter:eslint", "executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"], "outputs": ["{options.outputFile}"],
"options": { "options": {
"lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"] "lintFilePatterns": ["apps/explorer/**/*.{ts,tsx,js,jsx}"]
} }
}, },
"test": { "test": {
"executor": "@nx/jest:jest", "executor": "@nrwl/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/explorer"], "outputs": ["coverage/apps/explorer"],
"options": { "options": {
"jestConfig": "apps/explorer/jest.config.ts", "jestConfig": "apps/explorer/jest.config.ts",
"passWithNoTests": true "passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
} }
}, },
"generate-types": { "generate-types": {
"executor": "nx:run-commands", "executor": "@nrwl/workspace:run-commands",
"options": { "options": {
"commands": [ "commands": [
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/spec-update-v0.72.0-preview.2/specs/v0.72.0-preview.2/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types" "npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.71.4/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
] ]
} }
}, },
"build-netlify": { "build-netlify": {
"executor": "nx:run-commands", "executor": "@nrwl/workspace:run-commands",
"options": { "options": {
"commands": [ "commands": [
"cp apps/explorer/netlify.toml netlify.toml", "cp apps/explorer/netlify.toml netlify.toml",
@@ -91,7 +84,7 @@
} }
}, },
"build-spec": { "build-spec": {
"executor": "nx:run-commands", "executor": "@nrwl/workspace:run-commands",
"outputs": [], "outputs": [],
"options": { "options": {
"command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json" "command": "yarn tsc --project ./apps/explorer/tsconfig.spec.json"
@@ -1,15 +1,15 @@
import { useMemo } from 'react';
import type { AssetFieldsFragment } from '@vegaprotocol/assets'; import type { AssetFieldsFragment } from '@vegaprotocol/assets';
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets'; import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid'; import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react'; import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints'; import { BREAKPOINT_MD } from '../../config/breakpoints';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import type { RowClickedEvent, ColDef } from 'ag-grid-community'; import type { RowClickedEvent } from 'ag-grid-community';
type AssetsTableProps = { type AssetsTableProps = {
data: AssetFieldsFragment[] | null; data: AssetFieldsFragment[] | null;
@@ -31,58 +31,6 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
}; };
}, []); }, []);
const columnDefs = useMemo<ColDef[]>(
() => [
{ headerName: t('Symbol'), field: 'symbol' },
{ headerName: t('Name'), field: 'name' },
{
flex: 2,
headerName: t('ID'),
field: 'id',
hide: window.innerWidth < BREAKPOINT_MD,
},
{
colId: 'type',
headerName: t('Type'),
field: 'source.__typename',
hide: window.innerWidth < BREAKPOINT_MD,
valueFormatter: ({ value }: { value?: string }) =>
value ? AssetTypeMapping[value].value : '',
},
{
headerName: t('Status'),
field: 'status',
hide: window.innerWidth < BREAKPOINT_MD,
valueFormatter: ({ value }: { value?: string }) =>
value ? AssetStatusMapping[value].value : '',
},
{
colId: 'actions',
headerName: '',
sortable: false,
filter: false,
resizable: false,
wrapText: true,
field: 'id',
cellRenderer: ({
value,
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
value ? (
<ButtonLink
onClick={(e) => {
navigate(value);
}}
>
{t('View details')}
</ButtonLink>
) : (
''
),
},
],
[navigate]
);
return ( return (
<AgGrid <AgGrid
ref={ref} ref={ref}
@@ -98,11 +46,60 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
filterParams: { buttons: ['reset'] }, filterParams: { buttons: ['reset'] },
autoHeight: true, autoHeight: true,
}} }}
columnDefs={columnDefs}
suppressCellFocus={true} suppressCellFocus={true}
onRowClicked={({ data }: RowClickedEvent) => { onRowClicked={({ data }: RowClickedEvent) => {
navigate(data.id); navigate(data.id);
}} }}
/> >
<AgGridColumn headerName={t('Symbol')} field="symbol" />
<AgGridColumn headerName={t('Name')} field="name" />
<AgGridColumn
flex="2"
headerName={t('ID')}
field="id"
hide={window.innerWidth < BREAKPOINT_MD}
/>
<AgGridColumn
colId="type"
headerName={t('Type')}
field="source.__typename"
hide={window.innerWidth < BREAKPOINT_MD}
valueFormatter={({ value }: { value?: string }) =>
value && AssetTypeMapping[value].value
}
/>
<AgGridColumn
headerName={t('Status')}
field="status"
hide={window.innerWidth < BREAKPOINT_MD}
valueFormatter={({ value }: { value?: string }) =>
value && AssetStatusMapping[value].value
}
/>
<AgGridColumn
colId="actions"
headerName=""
sortable={false}
filter={false}
resizable={false}
wrapText={true}
field="id"
cellRenderer={({
value,
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
value ? (
<ButtonLink
onClick={(e) => {
navigate(value);
}}
>
{t('View details')}
</ButtonLink>
) : (
''
)
}
/>
</AgGrid>
); );
}; };
@@ -1,4 +1,5 @@
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit'; import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit';
import React from 'react';
export interface InfoBlockProps { export interface InfoBlockProps {
title: string; title: string;
@@ -1,98 +1,33 @@
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import PartyLink from './party-link'; import PartyLink from './party-link';
import { MockedProvider } from '@apollo/client/testing';
import { ExplorerNodeNamesDocument } from '../../../routes/validators/__generated__/NodeNames';
import { act } from 'react-dom/test-utils';
const zeroes =
'0000000000000000000000000000000000000000000000000000000000000000';
const mocks = [
{
request: {
query: ExplorerNodeNamesDocument,
},
result: {
data: {
nodesConnection: {
edges: [
{
node: {
id: '1',
name: 'Validator Node',
pubkey:
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e',
tmPubkey: 'tmPubkey1',
ethereumAddress: '0x123456789',
},
},
{
node: {
id: '2',
name: 'Node 2',
pubkey: 'pubkey2',
tmPubkey: 'tmPubkey2',
ethereumAddress: '0xabcdef123',
},
},
],
},
},
},
},
];
describe('PartyLink', () => { describe('PartyLink', () => {
it('renders Network for 000.000 party', () => { it('renders Network for 000.000 party', () => {
const screen = render( const zeroes =
<MockedProvider> '0000000000000000000000000000000000000000000000000000000000000000';
<PartyLink id={zeroes} /> const screen = render(<PartyLink id={zeroes} />);
</MockedProvider>
);
expect(screen.getByText('Network')).toBeInTheDocument(); expect(screen.getByText('Network')).toBeInTheDocument();
}); });
it('renders Network for network party', () => { it('renders Network for network party', () => {
const screen = render( const screen = render(<PartyLink id="network" />);
<MockedProvider>
<PartyLink id="network" />
</MockedProvider>
);
expect(screen.getByText('Network')).toBeInTheDocument(); expect(screen.getByText('Network')).toBeInTheDocument();
}); });
it('renders ID with no link for invalid party', () => { it('renders ID with no link for invalid party', () => {
const screen = render( const screen = render(<PartyLink id="this-party-is-not-valid" />);
<MockedProvider>
<PartyLink id="this-party-is-not-valid" />
</MockedProvider>
);
expect(screen.getByTestId('invalid-party')).toBeInTheDocument(); expect(screen.getByTestId('invalid-party')).toBeInTheDocument();
}); });
it('if the key is a validator, render their name instead', async () => {
const screen = render(
<MockedProvider mocks={mocks}>
<MemoryRouter>
<PartyLink id="13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e" />
</MemoryRouter>
</MockedProvider>
);
// Wait for hook to update with mock data
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
await expect(screen.getByText('Validator Node')).toBeInTheDocument();
});
it('links a valid party to the party page', () => { it('links a valid party to the party page', () => {
const aValidParty = const aValidParty =
'13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e'; '13464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6e';
const screen = render( const screen = render(
<MockedProvider> <MemoryRouter>
<MemoryRouter> <PartyLink id={aValidParty} />
<PartyLink id={aValidParty} /> </MemoryRouter>
</MemoryRouter>
</MockedProvider>
); );
const el = screen.getByText(aValidParty); const el = screen.getByText(aValidParty);
@@ -1,44 +1,22 @@
import { Routes } from '../../../routes/route-names'; import { Routes } from '../../../routes/route-names';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useMemo, type ComponentProps } from 'react'; import type { ComponentProps } from 'react';
import Hash from '../hash'; import Hash from '../hash';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error'; import { isValidPartyId } from '../../../routes/parties/id/components/party-id-error';
import { Icon, truncateMiddle } from '@vegaprotocol/ui-toolkit'; import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
import { useExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
import type { ExplorerNodeNamesQuery } from '../../../routes/validators/__generated__/NodeNames';
export const SPECIAL_CASE_NETWORK_ID = export const SPECIAL_CASE_NETWORK_ID =
'0000000000000000000000000000000000000000000000000000000000000000'; '0000000000000000000000000000000000000000000000000000000000000000';
export const SPECIAL_CASE_NETWORK = 'network'; export const SPECIAL_CASE_NETWORK = 'network';
export function getNameForParty(id: string, data?: ExplorerNodeNamesQuery) {
if (!data || data?.nodesConnection?.edges?.length === 0) {
return id;
}
const validator = data.nodesConnection.edges?.find((e) => {
return e?.node.pubkey === id;
});
if (validator) {
return validator.node.name;
}
return id;
}
export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & { export type PartyLinkProps = Partial<ComponentProps<typeof Link>> & {
id: string; id: string;
truncate?: boolean; truncate?: boolean;
}; };
const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => { const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
const { data } = useExplorerNodeNamesQuery();
const name = useMemo(() => getNameForParty(id, data), [data, id]);
const useName = name !== id;
// Some transactions will involve the 'network' party, which is alias for '000...000' // Some transactions will involve the 'network' party, which is alias for '000...000'
// The party page does not handle this nicely, so in this case we render the word 'Network' // The party page does not handle this nicely, so in this case we render the word 'Network'
if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) { if (id === SPECIAL_CASE_NETWORK || id === SPECIAL_CASE_NETWORK_ID) {
@@ -60,20 +38,13 @@ const PartyLink = ({ id, truncate = false, ...props }: PartyLinkProps) => {
} }
return ( return (
<span className="whitespace-nowrap"> <Link
{useName && <Icon size={4} name="cube" className="mr-2" />} className="underline font-mono"
<Link {...props}
className="underline font-mono" to={`/${Routes.PARTIES}/${id}`}
{...props} >
to={`/${Routes.PARTIES}/${id}`} <Hash text={truncate ? truncateMiddle(id) : id} />
> </Link>
{useName ? (
name
) : (
<Hash text={truncate ? truncateMiddle(id, 4, 4) : id} />
)}
</Link>
</span>
); );
}; };
@@ -1,9 +1,8 @@
import { useMemo } from 'react';
import type { MarketFieldsFragment } from '@vegaprotocol/markets'; import type { MarketFieldsFragment } from '@vegaprotocol/markets';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community'; import { AgGridColumn } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
@@ -40,34 +39,54 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
}; };
}, []); }, []);
const columnDefs = useMemo<ColDef[]>( return (
() => [ <AgGrid
{ ref={gridRef}
colId: 'code', rowData={data}
headerName: t('Code'), getRowId={({ data }: { data: MarketFieldsFragment }) => data.id}
field: 'tradableInstrument.instrument.code', overlayNoRowsTemplate={t('This chain has no markets')}
}, domLayout="autoHeight"
{ defaultColDef={{
colId: 'name', flex: 1,
headerName: t('Name'), resizable: true,
field: 'tradableInstrument.instrument.name', sortable: true,
}, filter: true,
{ filterParams: { buttons: ['reset'] },
headerName: t('Status'), autoHeight: true,
field: 'state', }}
hide: window.innerWidth <= BREAKPOINT_MD, suppressCellFocus={true}
valueGetter: ({ onRowClicked={({ data, event }: RowClickedEvent) => {
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
navigate(data.id);
}
}}
>
<AgGridColumn
colId="code"
headerName={t('Code')}
field="tradableInstrument.instrument.code"
/>
<AgGridColumn
colId="name"
headerName={t('Name')}
field="tradableInstrument.instrument.name"
/>
<AgGridColumn
headerName={t('Status')}
field="state"
hide={window.innerWidth <= BREAKPOINT_MD}
valueGetter={({
data, data,
}: VegaValueGetterParams<MarketFieldsFragment>) => { }: VegaValueGetterParams<MarketFieldsFragment>) => {
return data?.state ? MarketStateMapping[data?.state] : '-'; return data?.state ? MarketStateMapping[data?.state] : '-';
}, }}
}, />
{ <AgGridColumn
colId: 'asset', colId="asset"
headerName: t('Settlement asset'), headerName={t('Settlement asset')}
field: 'tradableInstrument.instrument.product.settlementAsset.symbol', field="tradableInstrument.instrument.product.settlementAsset.symbol"
hide: window.innerWidth <= BREAKPOINT_MD, hide={window.innerWidth <= BREAKPOINT_MD}
cellRenderer: ({ cellRenderer={({
data, data,
}: VegaICellRendererParams< }: VegaICellRendererParams<
MarketFieldsFragment, MarketFieldsFragment,
@@ -86,19 +105,19 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
) : ( ) : (
'' ''
); );
}, }}
}, />
{ <AgGridColumn
flex: 2, flex={2}
headerName: t('Market ID'), headerName={t('Market ID')}
field: 'id', field="id"
hide: window.innerWidth <= BREAKPOINT_MD, hide={window.innerWidth <= BREAKPOINT_MD}
}, />
{ <AgGridColumn
colId: 'actions', colId="actions"
headerName: '', headerName=""
field: 'id', field="id"
cellRenderer: ({ cellRenderer={({
value, value,
}: VegaICellRendererParams<MarketFieldsFragment, 'id'>) => }: VegaICellRendererParams<MarketFieldsFragment, 'id'>) =>
value ? ( value ? (
@@ -107,34 +126,9 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
</Link> </Link>
) : ( ) : (
'' ''
), )
},
],
[openAssetDetailsDialog]
);
return (
<AgGrid
ref={gridRef}
rowData={data}
getRowId={({ data }: { data: MarketFieldsFragment }) => data.id}
overlayNoRowsTemplate={t('This chain has no markets')}
domLayout="autoHeight"
defaultColDef={{
flex: 1,
resizable: true,
sortable: true,
filter: true,
filterParams: { buttons: ['reset'] },
autoHeight: true,
}}
columnDefs={columnDefs}
suppressCellFocus={true}
onRowClicked={({ data, event }: RowClickedEvent) => {
if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') {
navigate(data.id);
} }
}} />
/> </AgGrid>
); );
}; };
@@ -13,10 +13,6 @@ fragment ExplorerDeterministicOrderFields on Order {
remaining remaining
size size
rejectionReason rejectionReason
peggedOrder {
reference
offset
}
party { party {
id id
} }
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } }; export type ExplorerDeterministicOrderFieldsFragment = { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } };
export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
orderId: Types.Scalars['ID']; orderId: Types.Scalars['ID'];
@@ -11,7 +11,7 @@ export type ExplorerDeterministicOrderQueryVariables = Types.Exact<{
}>; }>;
export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, peggedOrder?: { __typename?: 'PeggedOrder', reference: Types.PeggedReference, offset: string } | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } }; export type ExplorerDeterministicOrderQuery = { __typename?: 'Query', orderByID: { __typename?: 'Order', id: string, type?: Types.OrderType | null, reference: string, status: Types.OrderStatus, version: string, createdAt: any, updatedAt?: any | null, expiresAt?: any | null, timeInForce: Types.OrderTimeInForce, price: string, side: Types.Side, remaining: string, size: string, rejectionReason?: Types.OrderRejectionReason | null, party: { __typename?: 'Party', id: string }, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, product: { __typename?: 'Future', quoteName: string } } } } } };
export const ExplorerDeterministicOrderFieldsFragmentDoc = gql` export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
fragment ExplorerDeterministicOrderFields on Order { fragment ExplorerDeterministicOrderFields on Order {
@@ -29,10 +29,6 @@ export const ExplorerDeterministicOrderFieldsFragmentDoc = gql`
remaining remaining
size size
rejectionReason rejectionReason
peggedOrder {
reference
offset
}
party { party {
id id
} }
@@ -12,7 +12,7 @@ type Amend = components['schemas']['v1OrderAmendment'];
function renderAmendOrderDetails( function renderAmendOrderDetails(
id: string, id: string,
version: number | undefined, version: number,
amend: Amend, amend: Amend,
mocks: MockedResponse[] mocks: MockedResponse[]
) { ) {
@@ -25,11 +25,7 @@ function renderAmendOrderDetails(
); );
} }
function renderExistingAmend( function renderExistingAmend(id: string, version: number, amend: Amend) {
id: string,
version: number | undefined,
amend: Amend
) {
const mocks = [ const mocks = [
{ {
request: { request: {
@@ -53,7 +49,6 @@ function renderExistingAmend(
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
price: '200', price: '200',
side: 'BUY', side: 'BUY',
peggedOrder: null,
remaining: '99', remaining: '99',
rejectionReason: 'rejection', rejectionReason: 'rejection',
reference: '123', reference: '123',
@@ -82,56 +77,6 @@ function renderExistingAmend(
}, },
}, },
}, },
{
request: {
query: ExplorerDeterministicOrderDocument,
variables: {
orderId: '123',
},
},
result: {
data: {
orderByID: {
__typename: 'Order',
id: '123',
type: 'GTT',
status: Schema.OrderStatus.STATUS_ACTIVE,
version: 100,
createdAt: '123',
updatedAt: '456',
expiresAt: '789',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
peggedOrder: null,
price: '200',
side: 'BUY',
remaining: '99',
rejectionReason: 'rejection',
reference: '123',
size: '200',
party: {
__typename: 'Party',
id: '234',
},
market: {
__typename: 'Market',
id: 'amend-to-order-latest-version',
state: 'STATUS_ACTIVE',
positionDecimalPlaces: 2,
decimalPlaces: '5',
tradableInstrument: {
instrument: {
name: 'amend-to-order-latest-version-test',
product: {
__typename: 'Future',
quoteName: '123',
},
},
},
},
},
},
},
},
{ {
request: { request: {
query: ExplorerMarketDocument, query: ExplorerMarketDocument,
@@ -212,15 +157,4 @@ describe('Amend order details', () => {
expect(await res.findByText('New price')).toBeInTheDocument(); expect(await res.findByText('New price')).toBeInTheDocument();
expect(await res.findByText('-7879')).toBeInTheDocument(); expect(await res.findByText('-7879')).toBeInTheDocument();
}); });
it('Fetches latest version when version is not specified', async () => {
const amend: Amend = {
price: '-7879',
};
const res = renderExistingAmend('123', undefined, amend);
expect(
await res.findByText('amend-to-order-latest-version')
).toBeInTheDocument();
});
}); });
@@ -12,7 +12,7 @@ import { wrapperClasses } from './deterministic-order-details';
export interface AmendOrderDetailsProps { export interface AmendOrderDetailsProps {
id: string; id: string;
amend: components['schemas']['v1OrderAmendment']; amend: components['schemas']['v1OrderAmendment'];
// Version to fetch. Latest is provided by default // Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
version?: number; version?: number;
} }
@@ -34,11 +34,13 @@ export function getSideDeltaColour(delta: string): string {
* @param param0 * @param param0
* @returns * @returns
*/ */
const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => { const AmendOrderDetails = ({
const variables = version ? { orderId: id, version } : { orderId: id }; id,
version = 0,
amend,
}: AmendOrderDetailsProps) => {
const { data, error } = useExplorerDeterministicOrderQuery({ const { data, error } = useExplorerDeterministicOrderQuery({
variables, variables: { orderId: id, version },
}); });
if (error || (data && !data.orderByID)) { if (error || (data && !data.orderByID)) {
@@ -5,7 +5,6 @@ import PriceInMarket from '../price-in-market/price-in-market';
import { Time } from '../time'; import { Time } from '../time';
import { sideText, statusText, tifFull, tifShort } from './lib/order-labels'; import { sideText, statusText, tifFull, tifShort } from './lib/order-labels';
import SizeInMarket from '../size-in-market/size-in-market'; import SizeInMarket from '../size-in-market/size-in-market';
import { TxOrderPeggedReference } from '../txs/details/order/tx-order-peg';
export interface DeterministicOrderDetailsProps { export interface DeterministicOrderDetailsProps {
id: string; id: string;
@@ -69,35 +68,25 @@ const DeterministicOrderDetails = ({
<span className="mx-5 text-base">@</span> <span className="mx-5 text-base">@</span>
<PriceInMarket price={o.price} marketId={o.market.id} /> <PriceInMarket price={o.price} marketId={o.market.id} />
</h2> </h2>
<p className="text-gray-200"> <p className="text-gray-500 mb-4">
In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />. In <MarketLink id={o.market.id} /> at <Time date={o.createdAt} />.
</p> </p>
{o.peggedOrder ? (
<p className="text-gray-200">
{t('Price peg')}:{' '}
<TxOrderPeggedReference
side={o.side}
reference={o.peggedOrder.reference}
offset={o.peggedOrder.offset}
marketId={o.market.id}
/>
</p>
) : null}
{o.reference ? ( {o.reference ? (
<p className="text-gray-500 mt-4"> <p className="text-gray-500 mb-4">
<span>{t('Reference')}</span>: {o.reference} <span>{t('Reference')}</span>: {o.reference}
</p> </p>
) : null} ) : null}
<div className="grid md:grid-cols-4 gap-x-6 mt-4"> <div className="grid md:grid-cols-4 gap-x-6">
<div className="mb-12 md:mb-0"> {version !== 0 ? null : (
<h2 className="text-2xl font-bold text-dark mb-4"> <div className="mb-12 md:mb-0">
{t('Status')} <h2 className="text-2xl font-bold text-dark mb-4">
</h2> {t('Status')}
<h5 className="text-lg font-medium text-gray-500 mb-0 capitalize"> </h2>
{statusText[o.status]} <h5 className="text-lg font-medium text-gray-500 mb-0 capitalize">
</h5> {statusText[o.status]}
</div> </h5>
</div>
)}
<div className="mb-12 md:mb-0"> <div className="mb-12 md:mb-0">
<h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2> <h2 className="text-2xl font-bold text-dark mb-4">{t('Size')}</h2>
@@ -106,6 +95,17 @@ const DeterministicOrderDetails = ({
</h5> </h5>
</div> </div>
{version !== 0 ? null : (
<div className="">
<h2 className="text-2xl font-bold text-dark mb-4">
{t('Remaining')}
</h2>
<h5 className="text-lg font-medium text-gray-500 mb-0">
<SizeInMarket size={o.remaining} marketId={o.market.id} />
</h5>
</div>
)}
<div className=""> <div className="">
<h2 className="text-2xl font-bold text-dark mb-4"> <h2 className="text-2xl font-bold text-dark mb-4">
{t('Version')} {t('Version')}
@@ -31,7 +31,6 @@ const mock = {
side: 'SIDE_BUY', side: 'SIDE_BUY',
remaining: '100', remaining: '100',
size: '100', size: '100',
peggedOrder: null,
party: { party: {
id: '456', id: '456',
}, },
@@ -1,6 +1,7 @@
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals'; import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import { VoteProgress } from '@vegaprotocol/proposals'; import { VoteProgress } from '@vegaprotocol/proposals';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
@@ -8,7 +9,7 @@ import type {
VegaValueFormatterParams, VegaValueFormatterParams,
} from '@vegaprotocol/datagrid'; } from '@vegaprotocol/datagrid';
import { useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import type { RowClickedEvent, ColDef } from 'ag-grid-community'; import type { RowClickedEvent } from 'ag-grid-community';
import { getDateTimeFormat } from '@vegaprotocol/utils'; import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
@@ -63,128 +64,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
title: '', title: '',
content: null, content: null,
}); });
const columnDefs = useMemo<ColDef[]>(
() => [
{
colId: 'title',
headerName: t('Title'),
field: 'rationale.title',
flex: 2,
wrapText: true,
},
{
colId: 'type',
maxWidth: 180,
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Type'),
field: 'terms.change.__typename',
},
{
maxWidth: 100,
headerName: t('State'),
field: 'state',
valueFormatter: ({
value,
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
return value ? ProposalStateMapping[value] : '-';
},
},
{
colId: 'voting',
maxWidth: 100,
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Voting'),
cellRenderer: ({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
if (data) {
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
const noTokens = new BigNumber(data.votes.no.totalTokens);
const totalTokensVoted = yesTokens.plus(noTokens);
const yesPercentage = totalTokensVoted.isZero()
? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
return (
<div className="uppercase flex h-full items-center justify-center pt-2">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
/>
</div>
);
}
return '-';
},
},
{
colId: 'cDate',
maxWidth: 150,
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Closing date'),
field: 'terms.closingDatetime',
valueFormatter: ({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
'terms.closingDatetime'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
},
},
{
colId: 'eDate',
maxWidth: 150,
hide: window.innerWidth <= BREAKPOINT_MD,
headerName: t('Enactment date'),
field: 'terms.enactmentDatetime',
valueFormatte: ({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
'terms.enactmentDatetime'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
},
},
{
colId: 'actions',
minWidth: window.innerWidth > BREAKPOINT_MD ? 221 : 80,
maxWidth: 221,
sortable: false,
filter: false,
resizable: false,
cellRenderer: ({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
const proposalPage = tokenLink(
TOKEN_PROPOSAL.replace(':id', data?.id || '')
);
const openDialog = () => {
if (!data) return;
setDialog({
open: true,
title: data.rationale.title,
content: data.terms,
});
};
return (
<div className="pb-1">
<button className="underline max-md:hidden" onClick={openDialog}>
{t('View terms')}
</button>{' '}
<ExternalLink className="max-md:hidden" href={proposalPage}>
{t('Open in Governance')}
</ExternalLink>
<ExternalLink className="md:hidden" href={proposalPage}>
{t('Open')}
</ExternalLink>
</div>
);
},
},
],
[requiredMajorityPercentage, tokenLink]
);
return ( return (
<> <>
<AgGrid <AgGrid
@@ -203,7 +83,6 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
filterParams: { buttons: ['reset'] }, filterParams: { buttons: ['reset'] },
autoHeight: true, autoHeight: true,
}} }}
columnDefs={columnDefs}
suppressCellFocus={true} suppressCellFocus={true}
onRowClicked={({ data, event }: RowClickedEvent) => { onRowClicked={({ data, event }: RowClickedEvent) => {
if ( if (
@@ -215,7 +94,128 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
window.open(proposalPage, '_blank'); window.open(proposalPage, '_blank');
} }
}} }}
/> >
<AgGridColumn
colId="title"
headerName={t('Title')}
field="rationale.title"
flex={2}
wrapText={true}
/>
<AgGridColumn
colId="type"
maxWidth={180}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Type')}
field="terms.change.__typename"
/>
<AgGridColumn
maxWidth={100}
headerName={t('State')}
field="state"
valueFormatter={({
value,
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) => {
return value ? ProposalStateMapping[value] : '-';
}}
/>
<AgGridColumn
colId="voting"
maxWidth={100}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Voting')}
cellRenderer={({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
if (data) {
const yesTokens = new BigNumber(data.votes.yes.totalTokens);
const noTokens = new BigNumber(data.votes.no.totalTokens);
const totalTokensVoted = yesTokens.plus(noTokens);
const yesPercentage = totalTokensVoted.isZero()
? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
return (
<div className="uppercase flex h-full items-center justify-center pt-2">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
/>
</div>
);
}
return '-';
}}
/>
<AgGridColumn
colId="cDate"
maxWidth={150}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Closing date')}
field="terms.closingDatetime"
valueFormatter={({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
'terms.closingDatetime'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
}}
/>
<AgGridColumn
colId="eDate"
maxWidth={150}
hide={window.innerWidth <= BREAKPOINT_MD}
headerName={t('Enactment date')}
field="terms.enactmentDatetime"
valueFormatter={({
value,
}: VegaValueFormatterParams<
ProposalListFieldsFragment,
'terms.enactmentDatetime'
>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '-';
}}
/>
<AgGridColumn
colId="actions"
minWidth={window.innerWidth > BREAKPOINT_MD ? 221 : 80}
maxWidth={221}
sortable={false}
filter={false}
resizable={false}
cellRenderer={({
data,
}: VegaICellRendererParams<ProposalListFieldsFragment>) => {
const proposalPage = tokenLink(
TOKEN_PROPOSAL.replace(':id', data?.id || '')
);
const openDialog = () => {
if (!data) return;
setDialog({
open: true,
title: data.rationale.title,
content: data.terms,
});
};
return (
<div className="pb-1">
<button
className="underline max-md:hidden"
onClick={openDialog}
>
{t('View terms')}
</button>{' '}
<ExternalLink className="max-md:hidden" href={proposalPage}>
{t('Open in Governance')}
</ExternalLink>
<ExternalLink className="md:hidden" href={proposalPage}>
{t('Open')}
</ExternalLink>
</div>
);
}}
/>
</AgGrid>
<JsonViewerDialog <JsonViewerDialog
open={dialog.open} open={dialog.open}
onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })} onChange={(isOpen) => setDialog({ ...dialog, open: isOpen })}
@@ -1,4 +1,4 @@
import { Icon, Tooltip } from '@vegaprotocol/ui-toolkit'; import { Icon } from '@vegaprotocol/ui-toolkit';
// https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go // https://github.com/vegaprotocol/vega/blob/develop/core/blockchain/response.go
export const ErrorCodes = new Map([ export const ErrorCodes = new Map([
@@ -17,8 +17,6 @@ interface ChainResponseCodeProps {
code: number; code: number;
hideLabel?: boolean; hideLabel?: boolean;
error?: string; error?: string;
hideIfOk?: boolean;
small?: boolean;
} }
/** /**
@@ -30,21 +28,14 @@ export const ChainResponseCode = ({
code, code,
hideLabel = false, hideLabel = false,
error, error,
hideIfOk = false,
small = false,
}: ChainResponseCodeProps) => { }: ChainResponseCodeProps) => {
if (hideIfOk && code === 0) {
return null;
}
const isSuccess = successCodes.has(code); const isSuccess = successCodes.has(code);
const size = small ? 3 : 4;
const successColour = const successColour =
code === 71 ? '!fill-vega-orange' : '!fill-vega-green-600'; code === 71 ? 'fill-vega-orange' : 'fill-vega-green-600';
const icon = isSuccess ? ( const icon = isSuccess ? (
<Icon size={size} name="tick-circle" className={`${successColour}`} /> <Icon name="tick-circle" className={successColour} />
) : ( ) : (
<Icon size={size} name="cross" className="!fill-vega-pink-500" /> <Icon name="cross" className="fill-vega-pink-600" />
); );
const label = ErrorCodes.get(code) || 'Unknown response code'; const label = ErrorCodes.get(code) || 'Unknown response code';
@@ -53,28 +44,18 @@ export const ChainResponseCode = ({
error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error; error && error.length > 100 ? error.replace(/,/g, ',\r\n') : error;
return ( return (
<Tooltip <div title={`Response code: ${code} - ${label}`} className=" inline-block">
description={ <span
<span> className="mr-2"
Response code: {code} - {label} aria-label={isSuccess ? 'Success' : 'Warning'}
</span> role="img"
} >
> {icon}
<div className="mt-[-1px] inline-block"> </span>
<span {hideLabel ? null : <span>{label}</span>}
className="mr-2" {!hideLabel && !!displayError ? (
aria-label={isSuccess ? 'Success' : 'Warning'} <span className="ml-1 whitespace-pre">&mdash;&nbsp;{displayError}</span>
role="img" ) : null}
> </div>
{icon}
</span>
{hideLabel ? null : <span>{label}</span>}
{!hideLabel && !!displayError ? (
<span className="ml-1 whitespace-pre">
&mdash;&nbsp;{displayError}
</span>
) : null}
</div>
</Tooltip>
); );
}; };
@@ -1,113 +0,0 @@
import { render } from '@testing-library/react';
import type { TxDetailsOrderProps } from './tx-order-peg';
import { TxOrderPeggedReference, getMarketDecimals } from './tx-order-peg';
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
import { PeggedReference, Side } from '@vegaprotocol/types';
// Mock the useExplorerMarketQuery hook
jest.mock('../../../links/market-link/__generated__/Market', () => ({
useExplorerMarketQuery: jest.fn().mockReturnValue({
data: {
market: { decimalPlaces: 0 },
},
loading: false,
}),
}));
describe('getSettlementAsset', () => {
it('should return the decimal places if data is defined', () => {
const data = {
market: {
__typename: 'Market',
id: '123',
decimalPlaces: 8,
},
};
const result = getMarketDecimals(data as Partial<ExplorerMarketQuery>);
expect(result).toEqual(8);
});
it('should return 0 if data is undefined', () => {
const result = getMarketDecimals(undefined);
expect(result).toEqual(0);
});
});
describe('TxOrderPeggedReference', () => {
beforeEach(() => {
// Mock the useExplorerMarketQuery hook return value
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
data: {
settlementAsset: 'some-settlement-asset',
},
loading: false,
});
});
afterEach(() => {
jest.resetAllMocks();
});
it('should render the offset and reference correctly', () => {
const props: TxDetailsOrderProps = {
side: Side.SIDE_BUY,
offset: '10',
reference: PeggedReference.PEGGED_REFERENCE_MID,
marketId: 'some-market-id',
};
const { getByTestId } = render(<TxOrderPeggedReference {...props} />);
expect(getByTestId('pegged-reference')).toHaveTextContent('Mid + 10');
});
it('should return null if the reference is "PEGGED_REFERENCE_UNSPECIFIED"', () => {
const props: TxDetailsOrderProps = {
side: Side.SIDE_BUY,
offset: '10',
reference: 'PEGGED_REFERENCE_UNSPECIFIED',
marketId: 'some-market-id',
};
const { container } = render(<TxOrderPeggedReference {...props} />);
expect(container.firstChild).toBeNull();
});
it('should render the offset without formatting initially, then render the formatted version', () => {
const props: TxDetailsOrderProps = {
side: Side.SIDE_BUY,
offset: '10',
reference: PeggedReference.PEGGED_REFERENCE_BEST_ASK,
marketId: 'some-market-id',
};
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
data: null,
loading: true,
});
const screen = render(<TxOrderPeggedReference {...props} />);
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
'Ask + 10'
);
(useExplorerMarketQuery as jest.Mock).mockReturnValue({
data: {
market: {
decimalPlaces: 10,
},
},
loading: false,
});
screen.rerender(<TxOrderPeggedReference {...props} />);
expect(screen.getByTestId('pegged-reference')).toHaveTextContent(
'Ask + 0.000000001'
);
});
});
@@ -1,72 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { TableCell, TableRow } from '../../../table';
import type { VegaPeggedReference } from '../liquidity-provision/liquidity-provision-details';
import { Side, PeggedReferenceMapping } from '@vegaprotocol/types';
import { useExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
import type { ExplorerMarketQuery } from '../../../links/market-link/__generated__/Market';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
export interface TxDetailsOrderProps {
offset: string;
reference: VegaPeggedReference;
marketId: string;
side: Side;
}
export function getMarketDecimals(
data: ExplorerMarketQuery | undefined
): number {
return data?.market?.decimalPlaces || 0;
}
/**
* Summarises an order's peg
*/
export const TxOrderPeggedReferenceRow = ({
offset,
reference,
marketId,
side,
}: TxDetailsOrderProps) => {
return (
<TableRow modifier="bordered">
<TableCell>{t('Pegged order')}</TableCell>
<TableCell>
<TxOrderPeggedReference
side={side}
offset={offset}
reference={reference}
marketId={marketId}
/>
</TableCell>
</TableRow>
);
};
export const TxOrderPeggedReference = ({
offset,
reference,
marketId,
side,
}: TxDetailsOrderProps) => {
const { data, loading } = useExplorerMarketQuery({
variables: { id: marketId },
});
const direction = side === Side.SIDE_BUY ? '+' : '-';
const decimalPlaces = getMarketDecimals(data);
if (reference === 'PEGGED_REFERENCE_UNSPECIFIED') {
return null;
}
return (
<span data-testid="pegged-reference">
{PeggedReferenceMapping[reference]}&nbsp;
{direction}&nbsp;
{!loading && data
? addDecimalsFormatNumber(offset, decimalPlaces)
: offset}
</span>
);
};
@@ -6,32 +6,10 @@ import {
SPECIAL_CASE_NETWORK_ID, SPECIAL_CASE_NETWORK_ID,
} from '../../../../links/party-link/party-link'; } from '../../../../links/party-link/party-link';
import SizeInAsset from '../../../../size-in-asset/size-in-asset'; import SizeInAsset from '../../../../size-in-asset/size-in-asset';
import { AccountTypeMapping } from '@vegaprotocol/types';
import { AccountType } from '@vegaprotocol/types';
import { headerClasses, wrapperClasses } from '../transfer-details'; import { headerClasses, wrapperClasses } from '../transfer-details';
import type { components } from '../../../../../../types/explorer'; import type { Transfer } from '../transfer-details';
type Transfer = components['schemas']['commandsv1Transfer'];
type AccountTypes = components['schemas']['vegaAccountType'];
const AccountType: Record<AccountTypes, string> = {
ACCOUNT_TYPE_UNSPECIFIED: 'Unspecified',
ACCOUNT_TYPE_INSURANCE: 'Insurance',
ACCOUNT_TYPE_SETTLEMENT: 'Settlement',
ACCOUNT_TYPE_MARGIN: 'Margin',
ACCOUNT_TYPE_GENERAL: 'General',
ACCOUNT_TYPE_FEES_INFRASTRUCTURE: 'Infrastructure',
ACCOUNT_TYPE_FEES_LIQUIDITY: 'Liquidity',
ACCOUNT_TYPE_FEES_MAKER: 'Maker',
ACCOUNT_TYPE_BOND: 'Bond',
ACCOUNT_TYPE_EXTERNAL: 'External',
ACCOUNT_TYPE_GLOBAL_INSURANCE: 'Global Insurance',
ACCOUNT_TYPE_GLOBAL_REWARD: 'Global Reward',
ACCOUNT_TYPE_PENDING_TRANSFERS: 'Pending Transfers',
ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: 'Maker Paid Fees',
ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: 'Maker Received Fees',
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: 'LP Received Fees',
ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: 'Market Proposers',
ACCOUNT_TYPE_HOLDING: 'Holding',
};
interface TransferParticipantsProps { interface TransferParticipantsProps {
transfer: Transfer; transfer: Transfer;
@@ -52,22 +30,22 @@ export function TransferParticipants({
}: TransferParticipantsProps) { }: TransferParticipantsProps) {
// This mapping is required as the global account types require a type to be set, while // This mapping is required as the global account types require a type to be set, while
// the underlying protobufs allow for every field to be undefined. // the underlying protobufs allow for every field to be undefined.
const fromAcct: AccountTypes = const fromAcct =
transfer.fromAccountType && transfer.fromAccountType &&
transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED' transfer.fromAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
? transfer.fromAccountType ? AccountType[transfer.fromAccountType]
: 'ACCOUNT_TYPE_GENERAL'; : AccountType.ACCOUNT_TYPE_GENERAL;
const fromAccountTypeLabel: string = transfer.fromAccountType const fromAccountTypeLabel = transfer.fromAccountType
? AccountType[fromAcct] ? AccountTypeMapping[fromAcct]
: 'Unknown'; : 'Unknown';
const toAcct: AccountTypes = const toAcct =
transfer.toAccountType && transfer.toAccountType &&
transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED' transfer.toAccountType !== 'ACCOUNT_TYPE_UNSPECIFIED'
? transfer.toAccountType ? AccountType[transfer.toAccountType]
: 'ACCOUNT_TYPE_GENERAL'; : AccountType.ACCOUNT_TYPE_GENERAL;
const toAccountTypeLabel = transfer.fromAccountType const toAccountTypeLabel = transfer.fromAccountType
? AccountType[toAcct] ? AccountTypeMapping[toAcct]
: 'Unknown'; : 'Unknown';
return ( return (
@@ -27,9 +27,9 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
<div className={wrapperClasses}> <div className={wrapperClasses}>
<h2 className={headerClasses}>{t('Active epochs')}</h2> <h2 className={headerClasses}>{t('Active epochs')}</h2>
<div className="relative block rounded-lg py-6 text-center p-6"> <div className="relative block rounded-lg py-6 text-center p-6">
<div> <p>
<EpochOverview id={recurring.startEpoch} /> <EpochOverview id={recurring.startEpoch} />
</div> </p>
<p className="leading-10 my-2"> <p className="leading-10 my-2">
<IconForEpoch <IconForEpoch
start={recurring.startEpoch} start={recurring.startEpoch}
@@ -37,13 +37,13 @@ export function TransferRepeat({ recurring }: TransferRepeatProps) {
current={data?.epoch.id} current={data?.epoch.id}
/> />
</p> </p>
<div> <p>
{recurring.endEpoch ? ( {recurring.endEpoch ? (
<EpochOverview id={recurring.endEpoch} /> <EpochOverview id={recurring.endEpoch} />
) : ( ) : (
<span>{t('Forever')}</span> <span>{t('Forever')}</span>
)} )}
</div> </p>
</div> </div>
</div> </div>
); );
@@ -8,7 +8,7 @@ import { DispatchMetricLabels } from '@vegaprotocol/types';
export type Metric = components['schemas']['vegaDispatchMetric']; export type Metric = components['schemas']['vegaDispatchMetric'];
export type Strategy = components['schemas']['vegaDispatchStrategy']; export type Strategy = components['schemas']['vegaDispatchStrategy'];
const metricLabels: Record<Metric, string> = { const metricLabels = {
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric', DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
...DispatchMetricLabels, ...DispatchMetricLabels,
}; };
@@ -3,7 +3,7 @@ import { TransferRepeat } from './blocks/transfer-repeat';
import { TransferRewards } from './blocks/transfer-rewards'; import { TransferRewards } from './blocks/transfer-rewards';
import { TransferParticipants } from './blocks/transfer-participants'; import { TransferParticipants } from './blocks/transfer-participants';
export type Recurring = components['schemas']['commandsv1RecurringTransfer']; export type Recurring = components['schemas']['v1RecurringTransfer'];
export type Metric = components['schemas']['vegaDispatchMetric']; export type Metric = components['schemas']['vegaDispatchMetric'];
export const wrapperClasses = export const wrapperClasses =
@@ -1,86 +0,0 @@
import { render } from '@testing-library/react';
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
describe('TxDetailsLiquidityAmendment', () => {
const mockTxData = {
hash: 'test',
command: {
liquidityProvisionAmendment: {
marketId: 'BTC-USD',
commitmentAmount: 100,
fee: '0.01',
},
},
};
const mockPubKey = '123';
const mockBlockData = {
result: {
block: {
header: {
height: '123',
},
},
},
};
it('should render the component with correct data', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={mockTxData as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(getByText('Market')).toBeInTheDocument();
expect(getByText('BTC-USD')).toBeInTheDocument();
expect(getByText('Commitment amount')).toBeInTheDocument();
expect(getByText('100')).toBeInTheDocument();
expect(getByText('Fee')).toBeInTheDocument();
expect(getByText('1%')).toBeInTheDocument();
});
it('should display awaiting message when tx data is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={undefined}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
it('should display awaiting message when liquidityProvisionAmendment is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={{ command: {} } as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
});
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
import type { components } from '../../../../types/explorer'; import type { components } from '../../../../types/explorer';
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details'; import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
import PriceInMarket from '../../price-in-market/price-in-market'; import PriceInMarket from '../../price-in-market/price-in-market';
import BigNumber from 'bignumber.js';
export type LiquidityAmendment = export type LiquidityAmendment =
components['schemas']['v1LiquidityProvisionAmendment']; components['schemas']['v1LiquidityProvisionAmendment'];
@@ -35,10 +34,6 @@ export const TxDetailsLiquidityAmendment = ({
txData.command.liquidityProvisionAmendment; txData.command.liquidityProvisionAmendment;
const marketId: string = amendment.marketId || '-'; const marketId: string = amendment.marketId || '-';
const fee = amendment.fee
? new BigNumber(amendment.fee).times(100).toString()
: '-';
return ( return (
<> <>
<TableWithTbody className="mb-8" allowWrap={true}> <TableWithTbody className="mb-8" allowWrap={true}>
@@ -68,7 +63,7 @@ export const TxDetailsLiquidityAmendment = ({
{amendment.fee ? ( {amendment.fee ? (
<TableRow modifier="bordered"> <TableRow modifier="bordered">
<TableCell>{t('Fee')}</TableCell> <TableCell>{t('Fee')}</TableCell>
<TableCell>{fee}%</TableCell> <TableCell>{amendment.fee}%</TableCell>
</TableRow> </TableRow>
) : null} ) : null}
</TableWithTbody> </TableWithTbody>
@@ -1,86 +0,0 @@
import { render } from '@testing-library/react';
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
describe('TxDetailsLiquiditySubmission', () => {
const mockTxData = {
hash: 'test',
command: {
liquidityProvisionSubmission: {
marketId: 'BTC-USD',
commitmentAmount: 100,
fee: '0.01',
},
},
};
const mockPubKey = '123';
const mockBlockData = {
result: {
block: {
header: {
height: '123',
},
},
},
};
it('should render the component with correct data', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={mockTxData as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(getByText('Market')).toBeInTheDocument();
expect(getByText('BTC-USD')).toBeInTheDocument();
expect(getByText('Commitment amount')).toBeInTheDocument();
expect(getByText('100')).toBeInTheDocument();
expect(getByText('Fee')).toBeInTheDocument();
expect(getByText('1%')).toBeInTheDocument();
});
it('should display awaiting message when tx data is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={undefined}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
it('should display awaiting message when liquidityProvisionSubmission is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={{ command: {} } as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
});
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
import type { components } from '../../../../types/explorer'; import type { components } from '../../../../types/explorer';
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details'; import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
import PriceInMarket from '../../price-in-market/price-in-market'; import PriceInMarket from '../../price-in-market/price-in-market';
import BigNumber from 'bignumber.js';
export type LiquiditySubmission = export type LiquiditySubmission =
components['schemas']['v1LiquidityProvisionSubmission']; components['schemas']['v1LiquidityProvisionSubmission'];
@@ -34,10 +33,6 @@ export const TxDetailsLiquiditySubmission = ({
txData.command.liquidityProvisionSubmission; txData.command.liquidityProvisionSubmission;
const marketId: string = submission.marketId || '-'; const marketId: string = submission.marketId || '-';
const fee = submission.fee
? new BigNumber(submission.fee).times(100).toString()
: '-';
return ( return (
<> <>
<TableWithTbody className="mb-8" allowWrap={true}> <TableWithTbody className="mb-8" allowWrap={true}>
@@ -67,7 +62,7 @@ export const TxDetailsLiquiditySubmission = ({
{submission.fee ? ( {submission.fee ? (
<TableRow modifier="bordered"> <TableRow modifier="bordered">
<TableCell>{t('Fee')}</TableCell> <TableCell>{t('Fee')}</TableCell>
<TableCell>{fee}%</TableCell> <TableCell>{submission.fee}%</TableCell>
</TableRow> </TableRow>
) : null} ) : null}
</TableWithTbody> </TableWithTbody>
@@ -7,7 +7,6 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
import { txSignatureToDeterministicId } from '../lib/deterministic-ids'; import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
import DeterministicOrderDetails from '../../order-details/deterministic-order-details'; import DeterministicOrderDetails from '../../order-details/deterministic-order-details';
import Hash from '../../links/hash'; import Hash from '../../links/hash';
import { TxOrderPeggedReferenceRow } from './order/tx-order-peg';
interface TxDetailsOrderProps { interface TxDetailsOrderProps {
txData: BlockExplorerTransactionResult | undefined; txData: BlockExplorerTransactionResult | undefined;
@@ -30,8 +29,6 @@ export const TxDetailsOrder = ({
return <>{t('Awaiting Block Explorer transaction details')}</>; return <>{t('Awaiting Block Explorer transaction details')}</>;
} }
const marketId = txData.command.orderSubmission.marketId || '-'; const marketId = txData.command.orderSubmission.marketId || '-';
const reference = txData.command.orderSubmission.peggedOrder;
const side = txData.command.orderSubmission.side;
let deterministicId = ''; let deterministicId = '';
@@ -66,14 +63,6 @@ export const TxDetailsOrder = ({
<MarketLink id={marketId} /> <MarketLink id={marketId} />
</TableCell> </TableCell>
</TableRow> </TableRow>
{reference ? (
<TxOrderPeggedReferenceRow
side={side}
offset={reference.offset}
reference={reference.reference}
marketId={marketId}
/>
) : null}
</TableWithTbody> </TableWithTbody>
{deterministicId.length > 0 ? ( {deterministicId.length > 0 ? (
@@ -10,17 +10,13 @@ export interface FilterLabelProps {
*/ */
export function FilterLabel({ filters }: FilterLabelProps) { export function FilterLabel({ filters }: FilterLabelProps) {
if (!filters || filters.size !== 1) { if (!filters || filters.size !== 1) {
return ( return <span className="uppercase">{t('Filter')}</span>;
<span data-testid="filter-empty" className="uppercase">
{t('Filter')}
</span>
);
} }
return ( return (
<div data-testid="filter-selected"> <div>
<span className="uppercase">{t('Filters')}:</span>&nbsp; <span className="uppercase">{t('Filters')}:</span>&nbsp;
<code className="bg-vega-light-150 dark:bg-vega-light-300 px-2 rounded-md capitalize dark:text-black"> <code className="bg-vega-light-150 px-2 rounded-md capitalize">
{Array.from(filters)[0]} {Array.from(filters)[0]}
</code> </code>
</div> </div>
@@ -1,21 +0,0 @@
import { render, screen } from '@testing-library/react';
import { TxsFilter } from './tx-filter';
import type { FilterOption } from './tx-filter';
describe('TxsFilter', () => {
it('renders holding text when nothing is selected', () => {
const filters: Set<FilterOption> = new Set([]);
const setFilters = jest.fn();
render(<TxsFilter filters={filters} setFilters={setFilters} />);
expect(screen.getByTestId('filter-empty')).toBeInTheDocument();
expect(screen.getByText('Filter')).toBeInTheDocument();
});
it('renders the submit order filter as selected', () => {
const filters: Set<FilterOption> = new Set(['Submit Order']);
const setFilters = jest.fn();
render(<TxsFilter filters={filters} setFilters={setFilters} />);
expect(screen.getByTestId('filter-selected')).toBeInTheDocument();
expect(screen.getByText('Submit Order')).toBeInTheDocument();
});
});
@@ -91,7 +91,7 @@ export interface TxFilterProps {
* types. It allows a user to select one transaction type to view. Later * types. It allows a user to select one transaction type to view. Later
* it will support multiple selection, but until the API supports that it is * it will support multiple selection, but until the API supports that it is
* one or all. * one or all.
* @param filters null or Set of transaction types * @param filters null or Set of tranaction types
* @param setFilters A function to update the filters prop * @param setFilters A function to update the filters prop
* @returns * @returns
*/ */
@@ -100,15 +100,15 @@ export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
<DropdownMenu <DropdownMenu
modal={false} modal={false}
trigger={ trigger={
<DropdownMenuTrigger className="ml-0"> <DropdownMenuTrigger className="ml-2">
<Button size="xs" data-testid="filter-trigger"> <Button size="xs">
<FilterLabel filters={filters} /> <FilterLabel filters={filters} />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
} }
> >
<DropdownMenuContent> <DropdownMenuContent>
{filters.size > 0 ? null : ( {filters.size > 1 ? null : (
<> <>
<DropdownMenuCheckboxItem <DropdownMenuCheckboxItem
onCheckedChange={() => setFilters(new Set(AllFilterOptions))} onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
@@ -1,113 +0,0 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { TxsListNavigation } from './tx-list-navigation';
const NOOP = () => {
return;
};
describe('TxsListNavigation', () => {
it('renders transaction list navigation', () => {
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={NOOP}
previousPage={NOOP}
hasMoreTxs={true}
hasPreviousPage={true}
>
<span></span>
</TxsListNavigation>
);
expect(screen.getByText('Newer')).toBeInTheDocument();
expect(screen.getByText('Older')).toBeInTheDocument();
});
it('calls previousPage when "Newer" button is clicked', () => {
const previousPageMock = jest.fn();
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={NOOP}
previousPage={previousPageMock}
hasMoreTxs={true}
hasPreviousPage={true}
>
<span></span>
</TxsListNavigation>
);
fireEvent.click(screen.getByText('Newer'));
expect(previousPageMock).toHaveBeenCalledTimes(1);
});
it('calls nextPage when "Older" button is clicked', () => {
const nextPageMock = jest.fn();
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={nextPageMock}
previousPage={NOOP}
hasMoreTxs={true}
hasPreviousPage={true}
>
<span></span>
</TxsListNavigation>
);
fireEvent.click(screen.getByText('Older'));
expect(nextPageMock).toHaveBeenCalledTimes(1);
});
it('disables "Older" button if hasMoreTxs is false', () => {
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={NOOP}
previousPage={NOOP}
hasMoreTxs={false}
hasPreviousPage={false}
>
<span></span>
</TxsListNavigation>
);
expect(screen.getByText('Older')).toBeDisabled();
});
it('disables "Newer" button if hasPreviousPage is false', () => {
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={NOOP}
previousPage={NOOP}
hasMoreTxs={true}
hasPreviousPage={false}
>
<span></span>
</TxsListNavigation>
);
expect(screen.getByText('Newer')).toBeDisabled();
});
it('disables both buttons when more and previous are false', () => {
render(
<TxsListNavigation
refreshTxs={NOOP}
nextPage={NOOP}
previousPage={NOOP}
hasMoreTxs={false}
hasPreviousPage={false}
>
<span></span>
</TxsListNavigation>
);
expect(screen.getByText('Newer')).toBeDisabled();
expect(screen.getByText('Older')).toBeDisabled();
});
});
@@ -1,63 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { BlocksRefetch } from '../blocks';
import { Button } from '@vegaprotocol/ui-toolkit';
export interface TxListNavigationProps {
refreshTxs: () => void;
nextPage: () => void;
previousPage: () => void;
loading?: boolean;
hasPreviousPage: boolean;
hasMoreTxs: boolean;
children: React.ReactNode;
}
/**
* Displays a list of transactions with filters and controls to navigate through the list.
*
* @returns {JSX.Element} Transaction List and controls
*/
export const TxsListNavigation = ({
refreshTxs,
nextPage,
previousPage,
hasMoreTxs,
hasPreviousPage,
children,
loading = false,
}: TxListNavigationProps) => {
return (
<>
<menu className="mb-2 w-full ">{children}</menu>
<menu className="mb-2 w-full">
<BlocksRefetch refetch={refreshTxs} />
<div className="float-right">
<Button
className="mr-2"
size="xs"
disabled={!hasPreviousPage || loading}
onClick={() => {
previousPage();
}}
>
{t('Newer')}
</Button>
<Button
size="xs"
disabled={!hasMoreTxs || loading}
onClick={() => {
nextPage();
}}
>
{t('Older')}
</Button>
</div>
<div className="float-right mr-2">
{loading ? (
<span className="text-vega-light-300">{t('Loading...')}</span>
) : null}
</div>
</menu>
</>
);
};
@@ -16,7 +16,7 @@ interface StringMap {
const displayString: StringMap = { const displayString: StringMap = {
OrderSubmission: 'Order Submission', OrderSubmission: 'Order Submission',
'Submit Order': 'Order', 'Submit Order': 'Order',
OrderCancellation: 'Cancel order', OrderCancellation: 'Order Cancellation',
OrderAmendment: 'Order Amendment', OrderAmendment: 'Order Amendment',
VoteSubmission: 'Vote Submission', VoteSubmission: 'Vote Submission',
WithdrawSubmission: 'Withdraw Submission', WithdrawSubmission: 'Withdraw Submission',
@@ -24,7 +24,6 @@ const displayString: StringMap = {
LiquidityProvisionSubmission: 'LP order', LiquidityProvisionSubmission: 'LP order',
'Liquidity Provision Order': 'LP order', 'Liquidity Provision Order': 'LP order',
LiquidityProvisionCancellation: 'LP cancel', LiquidityProvisionCancellation: 'LP cancel',
'Cancel LiquidityProvision Order': 'LP cancel',
LiquidityProvisionAmendment: 'LP update', LiquidityProvisionAmendment: 'LP update',
'Amend LiquidityProvision Order': 'Amend LP', 'Amend LiquidityProvision Order': 'Amend LP',
ProposalSubmission: 'Governance Proposal', ProposalSubmission: 'Governance Proposal',
@@ -37,34 +36,12 @@ const displayString: StringMap = {
UndelegateSubmission: 'Undelegation', UndelegateSubmission: 'Undelegation',
KeyRotateSubmission: 'Key Rotation', KeyRotateSubmission: 'Key Rotation',
StateVariableProposal: 'State Variable', StateVariableProposal: 'State Variable',
'State Variable Proposal': 'State Variable',
Transfer: 'Transfer', Transfer: 'Transfer',
CancelTransfer: 'Cancel Transfer', CancelTransfer: 'Cancel Transfer',
'Cancel Transfer Funds': 'Cancel Transfer',
ValidatorHeartbeat: 'Heartbeat', ValidatorHeartbeat: 'Heartbeat',
'Validator Heartbeat': 'Heartbeat',
'Batch Market Instructions': 'Batch', 'Batch Market Instructions': 'Batch',
'Stop Orders Submission': 'Stop',
StopOrdersSubmission: 'Stop',
StopOrdersCancellation: 'Cancel stop',
'Stop Orders Cancellation': 'Cancel stop',
}; };
export function getLabelForOrderType(
orderType: string,
command: components['schemas']['v1InputData']
): string {
if (command.orderSubmission) {
if (command.orderSubmission.peggedOrder) {
return 'Peg';
}
if (command.orderSubmission.icebergOpts) {
return 'Iceberg';
}
}
return 'Order';
}
/** /**
* Given a proposal, will return a specific label * Given a proposal, will return a specific label
* @param chainEvent * @param chainEvent
@@ -136,8 +113,6 @@ export function getLabelForChainEvent(
return t('Signer threshold'); return t('Signer threshold');
} }
return t('Multisig update'); return t('Multisig update');
} else if (chainEvent.contractCall) {
return t('Contract call');
} }
return t('Chain Event'); return t('Chain Event');
} }
@@ -197,7 +172,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
return ( return (
<div <div
data-testid="tx-type" data-testid="tx-type"
className={`text-sm rounded-md leading-tight px-2 inline-block whitespace-nowrap ${colours}`} className={`text-sm rounded-md leading-none px-2 py-2 inline-block ${colours}`}
> >
{type} {type}
</div> </div>
@@ -1,4 +1,3 @@
import { MockedProvider } from '@apollo/client/testing';
import { TxsInfiniteListItem } from './txs-infinite-list-item'; import { TxsInfiniteListItem } from './txs-infinite-list-item';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
@@ -84,22 +83,21 @@ describe('Txs infinite list item', () => {
it('renders data correctly', () => { it('renders data correctly', () => {
render( render(
<MockedProvider> <MemoryRouter>
<MemoryRouter> <TxsInfiniteListItem
<TxsInfiniteListItem type="testType"
type="testType" submitter="testPubKey"
submitter="testPubKey" hash="testTxHash"
hash="testTxHash" block="1"
block="1" code={0}
code={0} command={{}}
command={{}} />
/> </MemoryRouter>
</MemoryRouter>
</MockedProvider>
); );
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash'); expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey'); expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType'); expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent('1'); expect(screen.getByTestId('tx-block')).toHaveTextContent('1');
expect(screen.getByTestId('tx-success')).toHaveTextContent('Success');
}); });
}); });
@@ -1,3 +1,4 @@
import React from 'react';
import { TruncatedLink } from '../truncate/truncated-link'; import { TruncatedLink } from '../truncate/truncated-link';
import { Routes } from '../../routes/route-names'; import { Routes } from '../../routes/route-names';
import { TxOrderType } from './tx-order-type'; import { TxOrderType } from './tx-order-type';
@@ -5,25 +6,8 @@ import type { BlockExplorerTransactionResult } from '../../routes/types/block-ex
import { toHex } from '../search/detect-search'; import { toHex } from '../search/detect-search';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code'; import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import isNumber from 'lodash/isNumber'; import isNumber from 'lodash/isNumber';
import { PartyLink } from '../links';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import type { Screen } from '@vegaprotocol/react-helpers';
import { useMemo } from 'react';
const DEFAULT_TRUNCATE_LENGTH = 7; const TRUNCATE_LENGTH = 10;
export function getIdTruncateLength(screen: Screen): number {
if (['xxxl', 'xxl'].includes(screen)) {
return 64;
} else if (['xl', 'lg', 'md'].includes(screen)) {
return 32;
}
return DEFAULT_TRUNCATE_LENGTH;
}
export function shouldTruncateParty(screen: Screen): boolean {
return !['xxxl', 'xxl', 'xl'].includes(screen);
}
export const TxsInfiniteListItem = ({ export const TxsInfiniteListItem = ({
hash, hash,
@@ -33,12 +17,6 @@ export const TxsInfiniteListItem = ({
block, block,
command, command,
}: Partial<BlockExplorerTransactionResult>) => { }: Partial<BlockExplorerTransactionResult>) => {
const { screenSize } = useScreenDimensions();
const idTruncateLength = useMemo(
() => getIdTruncateLength(screenSize),
[screenSize]
);
if ( if (
!hash || !hash ||
!submitter || !submitter ||
@@ -51,40 +29,68 @@ export const TxsInfiniteListItem = ({
} }
return ( return (
<tr <div
data-testid="transaction-row" data-testid="transaction-row"
className="transaction-row text-left items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item py-[2px]" className="flex items-center h-full border-t border-neutral-600 dark:border-neutral-800 txs-infinite-list-item grid grid-cols-10"
> >
<td <div
className="text-sm leading-none whitespace-nowrap font-mono" className="text-sm col-span-10 md:col-span-3 leading-none"
data-testid="tx-hash" data-testid="tx-hash"
> >
{isNumber(code) ? ( <span className="md:hidden uppercase text-vega-dark-300">
<ChainResponseCode code={code} hideLabel={true} hideIfOk={true} /> ID:&nbsp;
) : ( </span>
code
)}
<TruncatedLink <TruncatedLink
to={`/${Routes.TX}/${toHex(hash)}`} to={`/${Routes.TX}/${toHex(hash)}`}
text={hash} text={hash}
startChars={idTruncateLength} startChars={TRUNCATE_LENGTH}
endChars={0} endChars={TRUNCATE_LENGTH}
/> />
</td> </div>
<td className="text-sm leading-none"> <div
className="text-sm col-span-10 md:col-span-3 leading-none"
data-testid="pub-key"
>
<span className="md:hidden uppercase text-vega-dark-300">
By:&nbsp;
</span>
<TruncatedLink
to={`/${Routes.PARTIES}/${submitter}`}
text={submitter}
startChars={TRUNCATE_LENGTH}
endChars={TRUNCATE_LENGTH}
/>
</div>
<div className="text-sm col-span-5 md:col-span-2 leading-none flex items-center">
<TxOrderType orderType={type} command={command} /> <TxOrderType orderType={type} command={command} />
</td> </div>
<td className="text-sm leading-none" data-testid="pub-key"> <div
<PartyLink truncate={shouldTruncateParty(screenSize)} id={submitter} /> className="text-sm col-span-3 md:col-span-1 leading-none flex items-center"
</td> data-testid="tx-block"
<td className="text-sm items-center font-mono" data-testid="tx-block"> >
<span className="md:hidden uppercase text-vega-dark-300">
Block:&nbsp;
</span>
<TruncatedLink <TruncatedLink
to={`/${Routes.BLOCKS}/${block}`} to={`/${Routes.BLOCKS}/${block}`}
text={block} text={block}
startChars={5} startChars={TRUNCATE_LENGTH}
endChars={5} endChars={TRUNCATE_LENGTH}
/> />
</td> </div>
</tr> <div
className="text-sm col-span-2 md:col-span-1 leading-none flex items-center"
data-testid="tx-success"
>
<span className="md:hidden uppercase text-vega-dark-300">
Success&nbsp;
</span>
{isNumber(code) ? (
<ChainResponseCode code={code} hideLabel={true} />
) : (
code
)}
</div>
</div>
); );
}; };
@@ -1,9 +1,8 @@
import { TxsInfiniteList } from './txs-infinite-list'; import { TxsInfiniteList } from './txs-infinite-list';
import { render, screen } from '@testing-library/react'; import { render, screen, fireEvent, act } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response'; import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import { Side } from '@vegaprotocol/types'; import { Side } from '@vegaprotocol/types';
import { MockedProvider } from '@apollo/client/testing';
const generateTxs = (number: number): BlockExplorerTransactionResult[] => { const generateTxs = (number: number): BlockExplorerTransactionResult[] => {
return Array.from(Array(number)).map((_) => ({ return Array.from(Array(number)).map((_) => ({
@@ -41,7 +40,7 @@ describe('Txs infinite list', () => {
it('should display a "no items" message when no items provided', () => { it('should display a "no items" message when no items provided', () => {
render( render(
<TxsInfiniteList <TxsInfiniteList
txs={undefined as unknown as BlockExplorerTransactionResult[]} txs={undefined}
areTxsLoading={false} areTxsLoading={false}
hasMoreTxs={false} hasMoreTxs={false}
loadMoreTxs={() => null} loadMoreTxs={() => null}
@@ -49,7 +48,23 @@ describe('Txs infinite list', () => {
/> />
); );
expect(screen.getByTestId('emptylist')).toBeInTheDocument(); expect(screen.getByTestId('emptylist')).toBeInTheDocument();
expect(screen.getByText('No transactions found')).toBeInTheDocument(); expect(
screen.getByText('This chain has 0 transactions')
).toBeInTheDocument();
});
it('error is displayed at item level', () => {
const txs = generateTxs(1);
render(
<TxsInfiniteList
txs={txs}
areTxsLoading={false}
hasMoreTxs={false}
loadMoreTxs={() => null}
error={Error('test error!')}
/>
);
expect(screen.getByText('Cannot fetch transaction')).toBeInTheDocument();
}); });
it('item renders data of n length into list of n length', () => { it('item renders data of n length into list of n length', () => {
@@ -58,22 +73,85 @@ describe('Txs infinite list', () => {
const txs = generateTxs(7); const txs = generateTxs(7);
render( render(
<MemoryRouter> <MemoryRouter>
<MockedProvider> <TxsInfiniteList
<TxsInfiniteList txs={txs}
txs={txs} areTxsLoading={false}
areTxsLoading={false} hasMoreTxs={false}
hasMoreTxs={false} loadMoreTxs={() => null}
loadMoreTxs={() => null} error={undefined}
error={undefined} />
/>
</MockedProvider>
</MemoryRouter> </MemoryRouter>
); );
expect( expect(
screen screen
.getByTestId('transactions-list') .getByTestId('infinite-scroll-wrapper')
.querySelectorAll('.transaction-row') .querySelectorAll('.txs-infinite-list-item')
).toHaveLength(7); ).toHaveLength(7);
}); });
it('tries to load more items when required to initially fill the list', () => {
// For example, if initially rendering 15, the bottom of the list is
// in view of the viewport, and the callback should be executed
const txs = generateTxs(15);
const callback = jest.fn();
render(
<MemoryRouter>
<TxsInfiniteList
txs={txs}
areTxsLoading={false}
hasMoreTxs={true}
loadMoreTxs={callback}
error={undefined}
/>
</MemoryRouter>
);
expect(callback.mock.calls.length).toEqual(1);
});
it('does not try to load more items if there are no more', () => {
const txs = generateTxs(3);
const callback = jest.fn();
render(
<MemoryRouter>
<TxsInfiniteList
txs={txs}
areTxsLoading={false}
hasMoreTxs={false}
loadMoreTxs={callback}
error={undefined}
/>
</MemoryRouter>
);
expect(callback.mock.calls.length).toEqual(0);
});
it('loads more items is called when scrolled', () => {
const txs = generateTxs(14);
const callback = jest.fn();
render(
<MemoryRouter>
<TxsInfiniteList
txs={txs}
areTxsLoading={false}
hasMoreTxs={true}
loadMoreTxs={callback}
error={undefined}
/>
</MemoryRouter>
);
act(() => {
fireEvent.scroll(screen.getByTestId('infinite-scroll-wrapper'), {
target: { scrollY: 2000 },
});
});
expect(callback.mock.calls.length).toEqual(1);
});
}); });
@@ -1,4 +1,8 @@
import React, { useEffect, useRef } from 'react';
import { FixedSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { TxsInfiniteListItem } from './txs-infinite-list-item'; import { TxsInfiniteListItem } from './txs-infinite-list-item';
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response'; import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import EmptyList from '../empty-list/empty-list'; import EmptyList from '../empty-list/empty-list';
@@ -7,46 +11,82 @@ import { Loader } from '@vegaprotocol/ui-toolkit';
interface TxsInfiniteListProps { interface TxsInfiniteListProps {
hasMoreTxs: boolean; hasMoreTxs: boolean;
areTxsLoading: boolean | undefined; areTxsLoading: boolean | undefined;
txs: BlockExplorerTransactionResult[]; txs: BlockExplorerTransactionResult[] | undefined;
loadMoreTxs: () => void; loadMoreTxs: () => void;
error: Error | undefined; error: Error | undefined;
className?: string; className?: string;
hasFilters?: boolean;
} }
interface ItemProps { interface ItemProps {
tx: BlockExplorerTransactionResult; index: BlockExplorerTransactionResult;
style: React.CSSProperties;
isLoading: boolean;
error: Error | undefined;
} }
const Item = ({ tx }: ItemProps) => { // eslint-disable-next-line @typescript-eslint/no-empty-function
const { hash, submitter, type, command, block, code, index: blockIndex } = tx; const NOOP = () => {};
return (
<TxsInfiniteListItem const Item = ({ index, style, isLoading, error }: ItemProps) => {
type={type} let content;
code={code} if (error) {
command={command} content = t(`Cannot fetch transaction`);
submitter={submitter} } else if (isLoading) {
hash={hash} content = <Loader />;
block={block} } else {
index={blockIndex} const {
/> hash,
); submitter,
type,
command,
block,
code,
index: blockIndex,
} = index;
content = (
<TxsInfiniteListItem
type={type}
code={code}
command={command}
submitter={submitter}
hash={hash}
block={block}
index={blockIndex}
/>
);
}
return <div style={style}>{content}</div>;
}; };
export const TxsInfiniteList = ({ export const TxsInfiniteList = ({
hasMoreTxs,
areTxsLoading, areTxsLoading,
txs, txs,
loadMoreTxs,
error,
className, className,
hasFilters = false,
}: TxsInfiniteListProps) => { }: TxsInfiniteListProps) => {
if (!txs || txs.length === 0) { const { screenSize } = useScreenDimensions();
const isStacked = ['xs', 'sm'].includes(screenSize);
const infiniteLoaderRef = useRef<InfiniteLoader>(null);
const hasMountedRef = useRef(false);
useEffect(() => {
if (hasMountedRef.current) {
if (infiniteLoaderRef.current) {
infiniteLoaderRef.current.resetloadMoreItemsCache(true);
}
}
hasMountedRef.current = true;
}, [loadMoreTxs]);
if (!txs) {
if (!areTxsLoading) { if (!areTxsLoading) {
return ( return (
<EmptyList <EmptyList
heading={t('No transactions found')} heading={t('This chain has 0 transactions')}
label={ label={t('Check back soon')}
hasFilters ? t('Try a different filter') : t('Check back soon')
}
/> />
); );
} else { } else {
@@ -54,26 +94,57 @@ export const TxsInfiniteList = ({
} }
} }
// If there are more items to be loaded then add an extra row to hold a loading indicator.
const itemCount = hasMoreTxs ? txs.length + 1 : txs.length;
// Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
// eslint-disable-next-line @typescript-eslint/no-empty-function
const loadMoreItems = areTxsLoading ? NOOP : loadMoreTxs;
// Every row is loaded except for our loading indicator row.
const isItemLoaded = (index: number) => !hasMoreTxs || index < txs.length;
return ( return (
<div className="overflow-scroll"> <div className={className} data-testid="transactions-list">
<table className={className} data-testid="transactions-list"> <div className="lg:grid grid-cols-10 w-full mb-3 hidden text-vega-dark-300 uppercase">
<thead> <div className="col-span-3">
<tr className="w-full mb-3 text-vega-dark-300 uppercase text-left"> <span className="hidden xl:inline">{t('Transaction')} &nbsp;</span>
<th> <span>ID</span>
<span className="hidden xl:inline">{t('Txn')} &nbsp;</span> </div>
<span>ID</span> <div className="col-span-3">{t('Submitted By')}</div>
</th> <div className="col-span-2">{t('Type')}</div>
<th>{t('Type')}</th> <div className="col-span-1">{t('Block')}</div>
<th className="text-left">{t('From')}</th> <div className="col-span-1">{t('Success')}</div>
<th>{t('Block')}</th> </div>
</tr> <div data-testid="infinite-scroll-wrapper">
</thead> <InfiniteLoader
<tbody> isItemLoaded={isItemLoaded}
{txs.map((t) => ( itemCount={itemCount}
<Item key={t.hash} tx={t} /> loadMoreItems={loadMoreItems}
))} ref={infiniteLoaderRef}
</tbody> >
</table> {({ onItemsRendered, ref }) => (
<List
className="List"
height={995}
itemCount={itemCount}
itemSize={isStacked ? 134 : 50}
onItemsRendered={onItemsRendered}
ref={ref}
width={'100%'}
>
{({ index, style }) => (
<Item
index={txs[index]}
style={style}
isLoading={!isItemLoaded(index)}
error={error}
/>
)}
</List>
)}
</InfiniteLoader>
</div>
</div> </div>
); );
}; };
@@ -1,17 +1,23 @@
import { Table, TableRow } from '../table'; import { Routes } from '../../routes/route-names';
import { TruncatedLink } from '../truncate/truncated-link';
import { TxOrderType } from './tx-order-type';
import { Table, TableRow, TableCell } from '../table';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers'; import { useFetch } from '@vegaprotocol/react-helpers';
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response'; import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import isNumber from 'lodash/isNumber';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import { getTxsDataUrl } from '../../hooks/use-txs-data'; import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list'; import EmptyList from '../empty-list/empty-list';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
interface TxsPerBlockProps { interface TxsPerBlockProps {
blockHeight: string; blockHeight: string;
txCount: number; txCount: number;
} }
const truncateLength = 5;
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => { export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
const filters = `filters[block.height]=${blockHeight}`; const filters = `filters[block.height]=${blockHeight}`;
const url = getTxsDataUrl({ limit: txCount.toString(), filters }); const url = getTxsDataUrl({ limit: txCount.toString(), filters });
@@ -27,23 +33,53 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
<thead> <thead>
<TableRow modifier="bordered" className="font-mono"> <TableRow modifier="bordered" className="font-mono">
<td>{t('Transaction')}</td> <td>{t('Transaction')}</td>
<td>{t('Type')}</td>
<td>{t('From')}</td> <td>{t('From')}</td>
<td>{t('Block')}</td> <td>{t('Type')}</td>
<td>{t('Status')}</td>
</TableRow> </TableRow>
</thead> </thead>
<tbody> <tbody>
{data.transactions.map( {data.transactions.map(
({ hash, submitter, type, command, code, block }) => { ({ hash, submitter, type, command, code }) => {
return ( return (
<TxsInfiniteListItem <TableRow
block={block} modifier="bordered"
hash={hash} key={hash}
submitter={submitter} data-testid="transaction-row"
type={type} >
command={command} <TableCell
code={code} modifier="bordered"
/> className="pr-12 font-mono"
>
<TruncatedLink
to={`/${Routes.TX}/${hash}`}
text={hash}
startChars={truncateLength}
endChars={truncateLength}
/>
</TableCell>
<TableCell
modifier="bordered"
className="pr-12 font-mono"
>
<TruncatedLink
to={`/${Routes.PARTIES}/${submitter}`}
text={submitter}
startChars={truncateLength}
endChars={truncateLength}
/>
</TableCell>
<TableCell modifier="bordered">
<TxOrderType orderType={type} command={command} />
</TableCell>
<TableCell modifier="bordered" className="text">
{isNumber(code) ? (
<ChainResponseCode code={code} hideLabel={true} />
) : (
code
)}
</TableCell>
</TableRow>
); );
} }
)} )}
@@ -56,14 +56,10 @@ export function VoteIcon({
return ( return (
<div <div
className={`voteicon inline-block py-0 px-2 py rounded-md text-white whitespace-nowrap leading-tight sm align-top ${bg}`} className={`voteicon inline-block my-1 py-1 px-2 py rounded-md text-white leading-one sm align-top ${bg}`}
> >
<Icon <Icon name={icon} size={3} className={`mr-2 p-0 fill-${fill}`} />
name={icon} <span className={`text-base text-${text}`} data-testid="label">
size={3}
className={`mr-2 p-0 mb-[-1px] fill-${fill}`}
/>
<span className={`text-${text}`} data-testid="label">
{label} {label}
</span> </span>
</div> </div>
+37 -65
View File
@@ -10,18 +10,16 @@ import isNumber from 'lodash/isNumber';
export interface TxsStateProps { export interface TxsStateProps {
txsData: BlockExplorerTransactionResult[]; txsData: BlockExplorerTransactionResult[];
hasMoreTxs: boolean; hasMoreTxs: boolean;
cursor: string; lastCursor: string;
previousCursors: string[];
hasPreviousPage: boolean;
} }
export interface IUseTxsData { export interface IUseTxsData {
limit: number; limit?: number;
filters?: string; filters?: string;
} }
interface IGetTxsDataUrl { interface IGetTxsDataUrl {
limit: string; limit?: string;
filters?: string; filters?: string;
} }
@@ -42,89 +40,63 @@ export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
}; };
export const useTxsData = ({ limit, filters }: IUseTxsData) => { export const useTxsData = ({ limit, filters }: IUseTxsData) => {
const [ const [{ txsData, hasMoreTxs, lastCursor }, setTxsState] =
{ txsData, hasMoreTxs, cursor, previousCursors, hasPreviousPage }, useState<TxsStateProps>({
setTxsState, txsData: [],
] = useState<TxsStateProps>({ hasMoreTxs: true,
txsData: [], lastCursor: '',
hasMoreTxs: false, });
previousCursors: [],
cursor: '',
hasPreviousPage: false,
});
const url = getTxsDataUrl({ limit: limit.toString(), filters }); const url = getTxsDataUrl({ limit: limit?.toString(), filters });
const { const {
state: { data, error, loading }, state: { data, error, loading },
refetch, refetch,
} = useFetch<BlockExplorerTransactions>(url, {}, true); } = useFetch<BlockExplorerTransactions>(url, {}, false);
useEffect(() => { useEffect(() => {
if (!loading && data && isNumber(data.transactions.length)) { if (data && isNumber(data?.transactions?.length)) {
setTxsState((prev) => { setTxsState((prev) => ({
return { txsData: [...prev.txsData, ...data.transactions],
...prev, hasMoreTxs: data.transactions.length > 0,
txsData: data.transactions, lastCursor:
hasMoreTxs: data.transactions.length >= limit, data.transactions[data.transactions.length - 1]?.cursor || '',
cursor: data?.transactions.at(-1)?.cursor || '', }));
};
});
} }
}, [loading, setTxsState, data, limit]); }, [setTxsState, data]);
const nextPage = useCallback(() => {
const c = data?.transactions.at(0)?.cursor;
const newPreviousCursors = c ? [...previousCursors, c] : previousCursors;
useEffect(() => {
setTxsState((prev) => ({ setTxsState((prev) => ({
...prev, txsData: [],
hasPreviousPage: true, hasMoreTxs: true,
previousCursors: newPreviousCursors, lastCursor: '',
})); }));
}, [filters]);
const loadTxs = useCallback(() => {
return refetch({ return refetch({
limit, limit: limit,
before: cursor, before: lastCursor,
}); });
}, [data, previousCursors, cursor, limit, refetch]); }, [lastCursor, limit, refetch]);
const previousPage = useCallback(() => {
const previousCursor = [...previousCursors].pop();
const newPreviousCursors = previousCursors.slice(0, -1);
setTxsState((prev) => ({
...prev,
hasPreviousPage: newPreviousCursors.length > 0,
previousCursors: newPreviousCursors,
}));
return refetch({
limit,
before: previousCursor,
});
}, [previousCursors, limit, refetch]);
const refreshTxs = useCallback(async () => { const refreshTxs = useCallback(async () => {
setTxsState(() => ({ setTxsState((prev) => ({
...prev,
lastCursor: '',
hasMoreTxs: true,
txsData: [], txsData: [],
cursor: '',
previousCursors: [],
hasMoreTxs: false,
hasPreviousPage: false,
})); }));
}, [setTxsState]);
refetch({ limit });
}, [setTxsState, limit, refetch, filters]); // eslint-disable-line react-hooks/exhaustive-deps
return { return {
txsData, data,
loading, loading,
error, error,
txsData,
hasMoreTxs, hasMoreTxs,
hasPreviousPage, lastCursor,
previousCursors,
cursor,
refreshTxs, refreshTxs,
nextPage, loadTxs,
previousPage,
}; };
}; };
+1 -3
View File
@@ -21,7 +21,6 @@ import {
import { Footer } from '../components/footer/footer'; import { Footer } from '../components/footer/footer';
import { Header } from '../components/header'; import { Header } from '../components/header';
import { Routes } from './route-names'; import { Routes } from './route-names';
import { useExplorerNodeNamesLazyQuery } from './validators/__generated__/NodeNames';
const DialogsContainer = () => { const DialogsContainer = () => {
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore(); const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
@@ -40,7 +39,6 @@ export const Layout = () => {
const isHome = Boolean(useMatch(Routes.HOME)); const isHome = Boolean(useMatch(Routes.HOME));
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment(); const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto'; const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
useExplorerNodeNamesLazyQuery();
return ( return (
<> <>
@@ -51,7 +49,7 @@ export const Layout = () => {
'grid grid-rows-[auto_1fr_auto] grid-cols-1', 'grid grid-rows-[auto_1fr_auto] grid-cols-1',
'border-vega-light-200 dark:border-vega-dark-200', 'border-vega-light-200 dark:border-vega-dark-200',
'antialiased text-black dark:text-white', 'antialiased text-black dark:text-white',
'relative' 'overflow-hidden relative'
)} )}
> >
<div> <div>
@@ -2,15 +2,12 @@ import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import type { SourceType } from './oracle'; import type { SourceType } from './oracle';
import { OracleSigners } from './oracle-signers'; import { OracleSigners } from './oracle-signers';
import { MockedProvider } from '@apollo/client/testing';
function renderComponent(sourceType: SourceType) { function renderComponent(sourceType: SourceType) {
return ( return (
<MockedProvider> <MemoryRouter>
<MemoryRouter> <OracleSigners sourceType={sourceType} />
<OracleSigners sourceType={sourceType} /> </MemoryRouter>
</MemoryRouter>
</MockedProvider>
); );
} }
@@ -1,6 +1,6 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useScreenDimensions } from '@vegaprotocol/react-helpers'; import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import { useMemo, useState } from 'react'; import { useMemo } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { SubHeading } from '../../../components/sub-heading'; import { SubHeading } from '../../../components/sub-heading';
import { toNonHex } from '../../../components/search/detect-search'; import { toNonHex } from '../../../components/search/detect-search';
@@ -14,11 +14,8 @@ import { PartyBlockStake } from './components/party-block-stake';
import { PartyBlockAccounts } from './components/party-block-accounts'; import { PartyBlockAccounts } from './components/party-block-accounts';
import { isValidPartyId } from './components/party-id-error'; import { isValidPartyId } from './components/party-id-error';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/data-provider';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
const Party = () => { const Party = () => {
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const { party } = useParams<{ party: string }>(); const { party } = useParams<{ party: string }>();
useDocumentTitle(['Public keys', party || '-']); useDocumentTitle(['Public keys', party || '-']);
@@ -27,24 +24,10 @@ const Party = () => {
const partyId = toNonHex(party ? party : ''); const partyId = toNonHex(party ? party : '');
const { isMobile } = useScreenDimensions(); const { isMobile } = useScreenDimensions();
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]); const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
const baseFilters = `filters[tx.submitter]=${partyId}`; const filters = `filters[tx.submitter]=${partyId}`;
const f = const { hasMoreTxs, loadTxs, error, txsData, loading } = useTxsData({
filters && filters.size === 1 limit: 10,
? `${baseFilters}&filters[cmd.type]=${Array.from(filters)[0]}` filters,
: baseFilters;
const {
hasMoreTxs,
nextPage,
previousPage,
error,
refreshTxs,
loading,
txsData,
hasPreviousPage,
} = useTxsData({
limit: 25,
filters: f,
}); });
const variables = useMemo(() => ({ partyId }), [partyId]); const variables = useMemo(() => ({ partyId }), [partyId]);
@@ -98,24 +81,14 @@ const Party = () => {
</div> </div>
<SubHeading>{t('Transactions')}</SubHeading> <SubHeading>{t('Transactions')}</SubHeading>
<TxsListNavigation
refreshTxs={refreshTxs}
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} />
</TxsListNavigation>
{!error && txsData ? ( {!error && txsData ? (
<TxsInfiniteList <TxsInfiniteList
hasMoreTxs={hasMoreTxs} hasMoreTxs={hasMoreTxs}
areTxsLoading={loading} areTxsLoading={loading}
txs={txsData} txs={txsData}
loadMoreTxs={nextPage} loadMoreTxs={loadTxs}
error={error} error={error}
className="mb-28 w-full" className="mb-28"
/> />
) : ( ) : (
<Splash> <Splash>
+13 -32
View File
@@ -1,14 +1,14 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { RouteTitle } from '../../../components/route-title'; import { RouteTitle } from '../../../components/route-title';
import { BlocksRefetch } from '../../../components/blocks';
import { TxsInfiniteList } from '../../../components/txs'; import { TxsInfiniteList } from '../../../components/txs';
import { useTxsData } from '../../../hooks/use-txs-data'; import { useTxsData } from '../../../hooks/use-txs-data';
import { useDocumentTitle } from '../../../hooks/use-document-title'; import { useDocumentTitle } from '../../../hooks/use-document-title';
import { useState } from 'react'; import { useState } from 'react';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter'; import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { TxsListNavigation } from '../../../components/txs/tx-list-navigation';
const BE_TXS_PER_REQUEST = 25; const BE_TXS_PER_REQUEST = 15;
export const TxsList = () => { export const TxsList = () => {
useDocumentTitle(['Transactions']); useDocumentTitle(['Transactions']);
@@ -21,11 +21,6 @@ export const TxsList = () => {
); );
}; };
/**
* Displays a list of transactions with filters and controls to navigate through the list.
*
* @returns {JSX.Element} Transaction List and controls
*/
export const TxsListFiltered = () => { export const TxsListFiltered = () => {
const [filters, setFilters] = useState(new Set(AllFilterOptions)); const [filters, setFilters] = useState(new Set(AllFilterOptions));
@@ -34,40 +29,26 @@ export const TxsListFiltered = () => {
? `filters[cmd.type]=${Array.from(filters)[0]}` ? `filters[cmd.type]=${Array.from(filters)[0]}`
: ''; : '';
const { const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
hasMoreTxs, useTxsData({
nextPage, limit: BE_TXS_PER_REQUEST,
previousPage, filters: f,
error, });
refreshTxs,
loading,
txsData,
hasPreviousPage,
} = useTxsData({
limit: BE_TXS_PER_REQUEST,
filters: f,
});
return ( return (
<> <>
<TxsListNavigation <menu className="mb-2">
refreshTxs={refreshTxs} <BlocksRefetch refetch={refreshTxs} />
nextPage={nextPage}
previousPage={previousPage}
hasPreviousPage={hasPreviousPage}
loading={loading}
hasMoreTxs={hasMoreTxs}
>
<TxsFilter filters={filters} setFilters={setFilters} /> <TxsFilter filters={filters} setFilters={setFilters} />
</TxsListNavigation> </menu>
<TxsInfiniteList <TxsInfiniteList
hasFilters={filters.size > 0}
hasMoreTxs={hasMoreTxs} hasMoreTxs={hasMoreTxs}
areTxsLoading={loading} areTxsLoading={loading}
txs={txsData} txs={txsData}
loadMoreTxs={nextPage} loadMoreTxs={loadTxs}
error={error} error={error}
className="mb-28 w-full min-w-[400px]" className="mb-28"
/> />
</> </>
); );
@@ -1,11 +1,10 @@
import { BrowserRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { TxDetails } from './tx-details'; import { TxDetails } from './tx-details';
import type { import type {
BlockExplorerTransactionResult, BlockExplorerTransactionResult,
ValidatorHeartbeat, ValidatorHeartbeat,
} from '../../../routes/types/block-explorer-response'; } from '../../../routes/types/block-explorer-response';
import { MemoryRouter } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
// Note: Long enough that there is a truncated output and a full output // Note: Long enough that there is a truncated output and a full output
const pubKey = const pubKey =
@@ -28,11 +27,9 @@ const txData: BlockExplorerTransactionResult = {
}; };
const renderComponent = (txData: BlockExplorerTransactionResult) => ( const renderComponent = (txData: BlockExplorerTransactionResult) => (
<MemoryRouter> <Router>
<MockedProvider> <TxDetails txData={txData} pubKey={pubKey} />
<TxDetails txData={txData} pubKey={pubKey} /> </Router>
</MockedProvider>
</MemoryRouter>
); );
describe('Transaction details', () => { describe('Transaction details', () => {
@@ -1,13 +0,0 @@
query ExplorerNodeNames {
nodesConnection {
edges {
node {
id
name
pubkey
tmPubkey
ethereumAddress
}
}
}
}
@@ -1,53 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type ExplorerNodeNamesQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerNodeNamesQuery = { __typename?: 'Query', nodesConnection: { __typename?: 'NodesConnection', edges?: Array<{ __typename?: 'NodeEdge', node: { __typename?: 'Node', id: string, name: string, pubkey: string, tmPubkey: string, ethereumAddress: string } } | null> | null } };
export const ExplorerNodeNamesDocument = gql`
query ExplorerNodeNames {
nodesConnection {
edges {
node {
id
name
pubkey
tmPubkey
ethereumAddress
}
}
}
}
`;
/**
* __useExplorerNodeNamesQuery__
*
* To run a query within a React component, call `useExplorerNodeNamesQuery` and pass it any options that fit your needs.
* When your component renders, `useExplorerNodeNamesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useExplorerNodeNamesQuery({
* variables: {
* },
* });
*/
export function useExplorerNodeNamesQuery(baseOptions?: Apollo.QueryHookOptions<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>(ExplorerNodeNamesDocument, options);
}
export function useExplorerNodeNamesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>(ExplorerNodeNamesDocument, options);
}
export type ExplorerNodeNamesQueryHookResult = ReturnType<typeof useExplorerNodeNamesQuery>;
export type ExplorerNodeNamesLazyQueryHookResult = ReturnType<typeof useExplorerNodeNamesLazyQuery>;
export type ExplorerNodeNamesQueryResult = Apollo.QueryResult<ExplorerNodeNamesQuery, ExplorerNodeNamesQueryVariables>;
+3 -2
View File
@@ -1,5 +1,6 @@
@import 'ag-grid-community/styles/ag-grid.css'; @import 'ag-grid-community/dist/styles/ag-grid.css';
@import 'ag-grid-community/styles/ag-theme-balham.css'; @import 'ag-grid-community/dist/styles/ag-theme-balham.css';
@import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css';
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@tailwind base; @tailwind base;
+72 -398
View File
@@ -3,7 +3,7 @@
* Do not make direct changes to the file. * Do not make direct changes to the file.
*/ */
/** OneOf type helpers */ /** Type helpers */
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }; type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T | U extends object type XOR<T, U> = T | U extends object
? (Without<T, U> & U) | (Without<U, T> & T) ? (Without<T, U> & U) | (Without<U, T> & T)
@@ -41,8 +41,6 @@ export interface paths {
}; };
} }
export type webhooks = Record<string, never>;
export interface components { export interface components {
schemas: { schemas: {
/** /**
@@ -103,17 +101,6 @@ export interface components {
| 'TIME_IN_FORCE_FOK' | 'TIME_IN_FORCE_FOK'
| 'TIME_IN_FORCE_GFA' | 'TIME_IN_FORCE_GFA'
| 'TIME_IN_FORCE_GFN'; | 'TIME_IN_FORCE_GFN';
/**
* @description - EXPIRY_STRATEGY_UNSPECIFIED: Never valid
* - EXPIRY_STRATEGY_CANCELS: Stop order should be cancelled if the expiry time is reached.
* - EXPIRY_STRATEGY_SUBMIT: Order should be submitted if the expiry time is reached.
* @default EXPIRY_STRATEGY_UNSPECIFIED
* @enum {string}
*/
readonly StopOrderExpiryStrategy:
| 'EXPIRY_STRATEGY_UNSPECIFIED'
| 'EXPIRY_STRATEGY_CANCELS'
| 'EXPIRY_STRATEGY_SUBMIT';
/** /**
* @default METHOD_UNSPECIFIED * @default METHOD_UNSPECIFIED
* @enum {string} * @enum {string}
@@ -156,36 +143,6 @@ export interface components {
/** Type of transaction */ /** Type of transaction */
readonly type?: string; readonly type?: string;
}; };
/** Request for cancelling a recurring transfer */
readonly commandsv1CancelTransfer: {
/** @description Transfer ID of the transfer to cancel. */
readonly transferId?: string;
};
/** Specific details for a one off transfer */
readonly commandsv1OneOffTransfer: {
/**
* Format: int64
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
*/
readonly deliverOn?: string;
};
/** Specific details for a recurring transfer */
readonly commandsv1RecurringTransfer: {
/** @description Optional parameter defining how a transfer is dispatched. */
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/** @description Factor needs to be > 0. */
readonly factor?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
/** Transfer initiated by a party */ /** Transfer initiated by a party */
readonly commandsv1Transfer: { readonly commandsv1Transfer: {
/** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */ /** @description Amount to be taken from the source account. This field is an unsigned integer scaled to the asset's decimal places. */
@@ -197,8 +154,8 @@ export interface components {
* should be taken. * should be taken.
*/ */
readonly fromAccountType?: components['schemas']['vegaAccountType']; readonly fromAccountType?: components['schemas']['vegaAccountType'];
readonly oneOff?: components['schemas']['commandsv1OneOffTransfer']; readonly oneOff?: components['schemas']['v1OneOffTransfer'];
readonly recurring?: components['schemas']['commandsv1RecurringTransfer']; readonly recurring?: components['schemas']['v1RecurringTransfer'];
/** @description Reference to be attached to the transfer. */ /** @description Reference to be attached to the transfer. */
readonly reference?: string; readonly reference?: string;
/** @description Public key of the destination account. */ /** @description Public key of the destination account. */
@@ -214,19 +171,8 @@ export interface components {
}; };
readonly protobufAny: { readonly protobufAny: {
readonly '@type'?: string; readonly '@type'?: string;
[key: string]: unknown; [key: string]: unknown | undefined;
}; };
/**
* @description `NullValue` is a singleton enumeration to represent the null value for the
* `Value` type union.
*
* The JSON representation for `NullValue` is JSON `null`.
*
* - NULL_VALUE: Null value.
* @default NULL_VALUE
* @enum {string}
*/
readonly protobufNullValue: 'NULL_VALUE';
/** Used to announce a node as a new pending validator */ /** Used to announce a node as a new pending validator */
readonly v1AnnounceNode: { readonly v1AnnounceNode: {
/** @description AvatarURL of the validator. */ /** @description AvatarURL of the validator. */
@@ -279,19 +225,18 @@ export interface components {
readonly amendments?: readonly components['schemas']['v1OrderAmendment'][]; readonly amendments?: readonly components['schemas']['v1OrderAmendment'][];
/** @description List of order cancellations to be processed sequentially. */ /** @description List of order cancellations to be processed sequentially. */
readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][]; readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][];
/** @description List of stop order cancellations to be processed sequentially. */
readonly stopOrdersCancellation?: readonly components['schemas']['v1StopOrdersCancellation'][];
/** @description List of stop order submissions to be processed sequentially. */
readonly stopOrdersSubmission?: readonly components['schemas']['v1StopOrdersSubmission'][];
/** @description List of order submissions to be processed sequentially. */ /** @description List of order submissions to be processed sequentially. */
readonly submissions?: readonly components['schemas']['v1OrderSubmission'][]; readonly submissions?: readonly components['schemas']['v1OrderSubmission'][];
}; };
/** Request for cancelling a recurring transfer */
readonly v1CancelTransfer: {
/** @description Transfer ID of the transfer to cancel. */
readonly transferId?: string;
};
/** Event forwarded to the Vega network to provide information on events happening on other networks */ /** Event forwarded to the Vega network to provide information on events happening on other networks */
readonly v1ChainEvent: { readonly v1ChainEvent: {
/** @description Built-in asset event. */ /** @description Built-in asset event. */
readonly builtin?: components['schemas']['vegaBuiltinAssetEvent']; readonly builtin?: components['schemas']['vegaBuiltinAssetEvent'];
/** Arbitrary contract call */
readonly contractCall?: components['schemas']['vegaEthContractCallEvent'];
/** @description Ethereum ERC20 event. */ /** @description Ethereum ERC20 event. */
readonly erc20?: components['schemas']['vegaERC20Event']; readonly erc20?: components['schemas']['vegaERC20Event'];
/** @description Ethereum ERC20 multisig event. */ /** @description Ethereum ERC20 multisig event. */
@@ -356,19 +301,6 @@ export interface components {
/** Transaction corresponding to the hash */ /** Transaction corresponding to the hash */
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction']; readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
}; };
/** Iceberg order options */
readonly v1IcebergOpts: {
/**
* Format: uint64
* @description Minimum allowed remaining size of the order before it is replenished back to its peak size.
*/
readonly minimumVisibleSize?: string;
/**
* Format: uint64
* @description Size of the order that is made visible and can be traded with during the execution of a single order.
*/
readonly peakSize?: string;
};
readonly v1InfoResponse: { readonly v1InfoResponse: {
/** Commit hash from which the data node was built */ /** Commit hash from which the data node was built */
readonly commitHash?: string; readonly commitHash?: string;
@@ -393,7 +325,7 @@ export interface components {
*/ */
readonly blockHeight?: string; readonly blockHeight?: string;
/** @description Command to request cancelling a recurring transfer. */ /** @description Command to request cancelling a recurring transfer. */
readonly cancelTransfer?: components['schemas']['commandsv1CancelTransfer']; readonly cancelTransfer?: components['schemas']['v1CancelTransfer'];
/** /**
* @description Command used by a validator to submit an event forwarded to the Vega network to provide information * @description Command used by a validator to submit an event forwarded to the Vega network to provide information
* on events happening on other networks, to be used by a foreign chain * on events happening on other networks, to be used by a foreign chain
@@ -449,10 +381,6 @@ export interface components {
readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal']; readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal'];
/** @description Command used by a validator to submit a floating point value. */ /** @description Command used by a validator to submit a floating point value. */
readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal']; readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal'];
/** @description Command to cancel stop orders. */
readonly stopOrdersCancellation?: components['schemas']['v1StopOrdersCancellation'];
/** @description Command to submit a pair of stop orders. */
readonly stopOrdersSubmission?: components['schemas']['v1StopOrdersSubmission'];
/** @description Command to submit a transfer. */ /** @description Command to submit a transfer. */
readonly transfer?: components['schemas']['commandsv1Transfer']; readonly transfer?: components['schemas']['commandsv1Transfer'];
/** @description Command to remove tokens delegated to a validator. */ /** @description Command to remove tokens delegated to a validator. */
@@ -520,9 +448,9 @@ export interface components {
readonly commitmentAmount?: string; readonly commitmentAmount?: string;
/** @description Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers. */ /** @description Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers. */
readonly fee?: string; readonly fee?: string;
/** @description Market ID for the order. */ /** @description Market ID for the order, required field. */
readonly marketId?: string; readonly marketId?: string;
/** @description Reference to be added to every order created out of this liquidity provision submission. */ /** @description Reference to be added to every order created out of this liquidityProvisionSubmission. */
readonly reference?: string; readonly reference?: string;
/** @description Set of liquidity sell orders to meet the liquidity provision obligation. */ /** @description Set of liquidity sell orders to meet the liquidity provision obligation. */
readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][]; readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][];
@@ -602,6 +530,15 @@ export interface components {
| 'TYPE_STAKE_TOTAL_SUPPLY' | 'TYPE_STAKE_TOTAL_SUPPLY'
| 'TYPE_SIGNER_THRESHOLD_SET' | 'TYPE_SIGNER_THRESHOLD_SET'
| 'TYPE_GOVERNANCE_VALIDATE_ASSET'; | 'TYPE_GOVERNANCE_VALIDATE_ASSET';
/** Specific details for a one off transfer */
readonly v1OneOffTransfer: {
/**
* Format: int64
* @description Unix timestamp in nanoseconds. Time at which the
* transfer should be delivered into the To account.
*/
readonly deliverOn?: string;
};
/** Command to submit new Oracle data from third party providers */ /** Command to submit new Oracle data from third party providers */
readonly v1OracleDataSubmission: { readonly v1OracleDataSubmission: {
/** /**
@@ -659,12 +596,10 @@ export interface components {
readonly v1OrderSubmission: { readonly v1OrderSubmission: {
/** /**
* Format: int64 * Format: int64
* @description Timestamp in Unix nanoseconds for when the order will expire, * @description Timestamp for when the order will expire, in nanoseconds,
* required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`. * required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT`.
*/ */
readonly expiresAt?: string; readonly expiresAt?: string;
/** @description Parameters used to specify an iceberg order. */
readonly icebergOpts?: components['schemas']['v1IcebergOpts'];
/** @description Market ID for the order, required field. */ /** @description Market ID for the order, required field. */
readonly marketId?: string; readonly marketId?: string;
/** @description Used to specify the details for a pegged order. */ /** @description Used to specify the details for a pegged order. */
@@ -764,6 +699,23 @@ export interface components {
readonly v1PubKey: { readonly v1PubKey: {
readonly key?: string; readonly key?: string;
}; };
/** Specific details for a recurring transfer */
readonly v1RecurringTransfer: {
/** @description Optional parameter defining how a transfer is dispatched. */
readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy'];
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/** @description Factor needs to be > 0. */
readonly factor?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
/** /**
* @description Signature to authenticate a transaction and to be verified by the Vega * @description Signature to authenticate a transaction and to be verified by the Vega
* network. * network.
@@ -780,7 +732,7 @@ export interface components {
readonly version?: number; readonly version?: number;
}; };
readonly v1Signer: { readonly v1Signer: {
/** @description In case of an open oracle - Ethereum address will be submitted. */ /** In case of an open oracle - Ethereum address will be submitted */
readonly ethAddress?: components['schemas']['v1ETHAddress']; readonly ethAddress?: components['schemas']['v1ETHAddress'];
/** /**
* @description List of authorized public keys that signed the data for this * @description List of authorized public keys that signed the data for this
@@ -794,55 +746,6 @@ export interface components {
/** @description State value proposal details. */ /** @description State value proposal details. */
readonly proposal?: components['schemas']['vegaStateValueProposal']; readonly proposal?: components['schemas']['vegaStateValueProposal'];
}; };
/** Price and expiry configuration for a stop order */
readonly v1StopOrderSetup: {
/**
* Format: int64
* @description Optional expiry timestamp.
*/
readonly expiresAt?: string;
/** @description Strategy to adopt if the expiry time is reached. */
readonly expiryStrategy?: components['schemas']['StopOrderExpiryStrategy'];
/** @description Order to be submitted once the trigger is breached. */
readonly orderSubmission?: components['schemas']['v1OrderSubmission'];
/** @description Fixed price at which the order will be submitted. */
readonly price?: string;
/** @description Trailing percentage at which the order will be submitted. */
readonly trailingPercentOffset?: string;
};
/**
* Cancel a stop order.
* The following combinations are available:
* Empty object will cancel all stop orders for the party
* Market ID alone will cancel all stop orders in a market
* Market ID and order ID will cancel a specific stop order in a market
* If the stop order is part of an OCO, both stop orders will be cancelled
*/
readonly v1StopOrdersCancellation: {
/** @description Optional market ID. */
readonly marketId?: string;
/** @description Optional order ID. */
readonly stopOrderId?: string;
};
/**
* Stop order submission submits stops orders.
* It is possible to make a single stop order submission by
* specifying a single direction,
* or an OCO (One Cancels the Other) stop order submission
* by specifying a configuration for both directions
*/
readonly v1StopOrdersSubmission: {
/**
* @description Stop order that will be triggered
* if the price falls below a given trigger price.
*/
readonly fallsBelow?: components['schemas']['v1StopOrderSetup'];
/**
* @description Stop order that will be triggered
* if the price rises above a given trigger price.
*/
readonly risesAbove?: components['schemas']['v1StopOrderSetup'];
};
readonly v1UndelegateSubmission: { readonly v1UndelegateSubmission: {
/** /**
* @description Optional, if not specified = ALL. * @description Optional, if not specified = ALL.
@@ -919,7 +822,6 @@ export interface components {
* - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers * - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers
* - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers * - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers
* - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold * - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold
* - ACCOUNT_TYPE_HOLDING: Per asset account for holding in-flight unfilled orders' funds
* @default ACCOUNT_TYPE_UNSPECIFIED * @default ACCOUNT_TYPE_UNSPECIFIED
* @enum {string} * @enum {string}
*/ */
@@ -940,8 +842,7 @@ export interface components {
| 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES' | 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES'
| 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES' | 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES'
| 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES' | 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES'
| 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS' | 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS';
| 'ACCOUNT_TYPE_HOLDING';
/** Vega representation of an external asset */ /** Vega representation of an external asset */
readonly vegaAssetDetails: { readonly vegaAssetDetails: {
/** @description Vega built-in asset. */ /** @description Vega built-in asset. */
@@ -997,14 +898,6 @@ export interface components {
/** @description Vega network internal asset ID. */ /** @description Vega network internal asset ID. */
readonly vegaAssetId?: string; readonly vegaAssetId?: string;
}; };
readonly vegaCancelTransfer: {
/** Configuration for cancellation of a governance-initiated transfer */
readonly changes?: components['schemas']['vegaCancelTransferConfiguration'];
};
readonly vegaCancelTransferConfiguration: {
/** @description ID of the governance transfer proposal. */
readonly transferId?: string;
};
/** /**
* @description DataSourceDefinition represents the top level object that deals with data sources. * @description DataSourceDefinition represents the top level object that deals with data sources.
* DataSourceDefinition can be external or internal, with whatever number of data sources are defined * DataSourceDefinition can be external or internal, with whatever number of data sources are defined
@@ -1019,7 +912,6 @@ export interface components {
* It contains one of any of the defined `SourceType` variants. * It contains one of any of the defined `SourceType` variants.
*/ */
readonly vegaDataSourceDefinitionExternal: { readonly vegaDataSourceDefinitionExternal: {
readonly ethCall?: components['schemas']['vegaEthCallSpec'];
readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration']; readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration'];
}; };
/** /**
@@ -1255,64 +1147,6 @@ export interface components {
/** @description Address into which the bridge will release the funds. */ /** @description Address into which the bridge will release the funds. */
readonly receiverAddress?: string; readonly receiverAddress?: string;
}; };
/** @description Specifies a data source that derives its content from calling a read method on an Ethereum contract. */
readonly vegaEthCallSpec: {
/** @description The ABI of that contract. */
readonly abi?: readonly Record<string, never>[];
/** @description Ethereum address of the contract to call. */
readonly address?: string;
/**
* @description List of arguments to pass to method call.
* Protobuf 'Value' wraps an arbitrary JSON type that is mapped to an Ethereum type according to the ABI.
*/
readonly args?: readonly Record<string, never>[];
/** @description Name of the method on the contract to call. */
readonly method?: string;
/** @description Conditions for determining when to call the contract method. */
readonly trigger?: components['schemas']['vegaEthCallTrigger'];
};
/** @description Determines when the contract method should be called. */
readonly vegaEthCallTrigger: {
readonly timeTrigger?: components['schemas']['vegaEthTimeTrigger'];
};
/** Result of calling an arbitrary Ethereum contract method */
readonly vegaEthContractCallEvent: {
/**
* Format: uint64
* @description Ethereum block height.
*/
readonly blockHeight?: string;
/**
* Format: uint64
* @description Ethereum block time in Unix seconds.
*/
readonly blockTime?: string;
/**
* Format: byte
* @description Result of contract call, packed according to the ABI stored in the associated data source spec.
*/
readonly result?: string;
/** @description ID of the data source spec that triggered this contract call. */
readonly specId?: string;
};
/** @description Trigger for an Ethereum call based on the Ethereum block timestamp. Can be one-off or repeating. */
readonly vegaEthTimeTrigger: {
/**
* Format: uint64
* @description Repeat the call every n seconds after the inital call. If no time for initial call was specified, begin repeating immediately.
*/
readonly every?: string;
/**
* Format: uint64
* @description Trigger when the Ethereum time is greater or equal to this time, in Unix seconds.
*/
readonly initial?: string;
/**
* Format: uint64
* @description If repeating, stop once Ethereum time is greater than this time, in Unix seconds. If not set, then repeat indefinitely.
*/
readonly until?: string;
};
/** Future product configuration */ /** Future product configuration */
readonly vegaFutureProduct: { readonly vegaFutureProduct: {
/** @description Binding between the data source spec and the settlement data. */ /** @description Binding between the data source spec and the settlement data. */
@@ -1326,14 +1160,6 @@ export interface components {
/** @description Asset ID for the product's settlement asset. */ /** @description Asset ID for the product's settlement asset. */
readonly settlementAsset?: string; readonly settlementAsset?: string;
}; };
/**
* @default GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED
* @enum {string}
*/
readonly vegaGovernanceTransferType:
| 'GOVERNANCE_TRANSFER_TYPE_UNSPECIFIED'
| 'GOVERNANCE_TRANSFER_TYPE_ALL_OR_NOTHING'
| 'GOVERNANCE_TRANSFER_TYPE_BEST_EFFORT';
/** Instrument configuration */ /** Instrument configuration */
readonly vegaInstrumentConfiguration: { readonly vegaInstrumentConfiguration: {
/** @description Instrument code, human-readable shortcode used to describe the instrument. */ /** @description Instrument code, human-readable shortcode used to describe the instrument. */
@@ -1342,8 +1168,6 @@ export interface components {
readonly future?: components['schemas']['vegaFutureProduct']; readonly future?: components['schemas']['vegaFutureProduct'];
/** @description Instrument name. */ /** @description Instrument name. */
readonly name?: string; readonly name?: string;
/** @description Spot. */
readonly spot?: components['schemas']['vegaSpotProduct'];
}; };
readonly vegaKeyValueBundle: { readonly vegaKeyValueBundle: {
readonly key?: string; readonly key?: string;
@@ -1434,14 +1258,14 @@ export interface components {
/** @description Configuration of the new market. */ /** @description Configuration of the new market. */
readonly changes?: components['schemas']['vegaNewMarketConfiguration']; readonly changes?: components['schemas']['vegaNewMarketConfiguration'];
}; };
/** Configuration for a new futures market on Vega */ /** Configuration for a new market on Vega */
readonly vegaNewMarketConfiguration: { readonly vegaNewMarketConfiguration: {
/** /**
* Format: uint64 * Format: uint64
* @description Decimal places used for the new futures market, sets the smallest price increment on the book. * @description Decimal places used for the new market, sets the smallest price increment on the book.
*/ */
readonly decimalPlaces?: string; readonly decimalPlaces?: string;
/** @description New futures market instrument configuration. */ /** @description New market instrument configuration. */
readonly instrument?: components['schemas']['vegaInstrumentConfiguration']; readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */ /** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
readonly linearSlippageFactor?: string; readonly linearSlippageFactor?: string;
@@ -1454,11 +1278,11 @@ export interface components {
* price levels over which automated liquidity provision orders will be deployed. * price levels over which automated liquidity provision orders will be deployed.
*/ */
readonly lpPriceRange?: string; readonly lpPriceRange?: string;
/** @description Optional new futures market metadata, tags. */ /** @description Optional new market metadata, tags. */
readonly metadata?: readonly string[]; readonly metadata?: readonly string[];
/** /**
* Format: int64 * Format: int64
* @description Decimal places for order sizes, sets what size the smallest order / position on the futures market can be. * @description Decimal places for order sizes, sets what size the smallest order / position on the market can be.
*/ */
readonly positionDecimalPlaces?: string; readonly positionDecimalPlaces?: string;
/** @description Price monitoring parameters. */ /** @description Price monitoring parameters. */
@@ -1467,80 +1291,6 @@ export interface components {
readonly quadraticSlippageFactor?: string; readonly quadraticSlippageFactor?: string;
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */ /** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams']; readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Successor configuration. If this proposal is meant to succeed a given market, then this should be set. */
readonly successor?: components['schemas']['vegaSuccessorConfiguration'];
};
/** New spot market on Vega */
readonly vegaNewSpotMarket: {
/** @description Configuration of the new spot market. */
readonly changes?: components['schemas']['vegaNewSpotMarketConfiguration'];
};
/** Configuration for a new spot market on Vega */
readonly vegaNewSpotMarketConfiguration: {
/**
* Format: uint64
* @description Decimal places used for the new spot market, sets the smallest price increment on the book.
*/
readonly decimalPlaces?: string;
/** @description New spot market instrument configuration. */
readonly instrument?: components['schemas']['vegaInstrumentConfiguration'];
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/** @description Optional new spot market metadata, tags. */
readonly metadata?: readonly string[];
/**
* Format: int64
* @description Decimal places for order sizes, sets what size the smallest order / position on the spot market can be.
*/
readonly positionDecimalPlaces?: string;
/** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Specifies parameters related to target stake calculation. */
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
};
/** New governance transfer */
readonly vegaNewTransfer: {
/** @description Configuration for a new transfer. */
readonly changes?: components['schemas']['vegaNewTransferConfiguration'];
};
readonly vegaNewTransferConfiguration: {
/** Maximum amount to transfer */
readonly amount?: string;
/** ID of asset to transfer */
readonly asset?: string;
/**
* Specifies the account to transfer to, depending on the account type:
* Network treasury: leave empty
* Party: party's public key
* Market insurance pool: market ID
*/
readonly destination?: string;
/** Specifies the account type to transfer to: reward pool, party, network insurance pool, market insurance pool */
readonly destinationType?: components['schemas']['vegaAccountType'];
/** Maximum fraction of the source account's balance to transfer as a decimal - i.e. 0.1 = 10% of the balance */
readonly fractionOfBalance?: string;
readonly oneOff?: components['schemas']['vegaOneOffTransfer'];
readonly recurring?: components['schemas']['vegaRecurringTransfer'];
/** If network treasury, field is empty, otherwise uses the market ID */
readonly source?: string;
/** Source account type, such as network treasury, market insurance pool */
readonly sourceType?: components['schemas']['vegaAccountType'];
/**
* "All or nothing" or "best effort":
* All or nothing: Transfers the specified amount or does not transfer anything
* Best effort: Transfers the specified amount or the max allowable amount if this is less than the specified amount
*/
readonly transferType?: components['schemas']['vegaGovernanceTransferType'];
};
/** Specific details for a one off transfer */
readonly vegaOneOffTransfer: {
/**
* Format: int64
* @description Timestamp in Unix nanoseconds for when the transfer should be delivered into the receiver's account.
*/
readonly deliverOn?: string;
}; };
/** /**
* Type values for an order * Type values for an order
@@ -1619,8 +1369,6 @@ export interface components {
}; };
/** Terms for a governance proposal on Vega */ /** Terms for a governance proposal on Vega */
readonly vegaProposalTerms: { readonly vegaProposalTerms: {
/** @description Cancel a governance transfer. */
readonly cancelTransfer?: components['schemas']['vegaCancelTransfer'];
/** /**
* Format: int64 * Format: int64
* @description Timestamp as Unix time in seconds when voting closes for this proposal, * @description Timestamp as Unix time in seconds when voting closes for this proposal,
@@ -1640,39 +1388,20 @@ export interface components {
* and can be used to gauge community sentiment. * and can be used to gauge community sentiment.
*/ */
readonly newFreeform?: components['schemas']['vegaNewFreeform']; readonly newFreeform?: components['schemas']['vegaNewFreeform'];
/** @description Proposal change for creating new futures market on Vega. */ /** @description Proposal change for creating new market on Vega. */
readonly newMarket?: components['schemas']['vegaNewMarket']; readonly newMarket?: components['schemas']['vegaNewMarket'];
/** @description Proposal change for creating new spot market on Vega. */
readonly newSpotMarket?: components['schemas']['vegaNewSpotMarket'];
/** @description Proposal change for a governance transfer. */
readonly newTransfer?: components['schemas']['vegaNewTransfer'];
/** @description Proposal change for updating an asset. */ /** @description Proposal change for updating an asset. */
readonly updateAsset?: components['schemas']['vegaUpdateAsset']; readonly updateAsset?: components['schemas']['vegaUpdateAsset'];
/** @description Proposal change for modifying an existing futures market on Vega. */ /** @description Proposal change for modifying an existing market on Vega. */
readonly updateMarket?: components['schemas']['vegaUpdateMarket']; readonly updateMarket?: components['schemas']['vegaUpdateMarket'];
/** @description Proposal change for updating Vega network parameters. */ /** @description Proposal change for updating Vega network parameters. */
readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter']; readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter'];
/** @description Proposal change for modifying an existing spot market on Vega. */
readonly updateSpotMarket?: components['schemas']['vegaUpdateSpotMarket'];
/** /**
* Format: int64 * Format: int64
* @description Validation timestamp as Unix time in seconds. * @description Validation timestamp as Unix time in seconds.
*/ */
readonly validationTimestamp?: string; readonly validationTimestamp?: string;
}; };
/** Specific details for a recurring transfer */
readonly vegaRecurringTransfer: {
/**
* Format: uint64
* @description Last epoch at which this transfer shall be paid.
*/
readonly endEpoch?: string;
/**
* Format: uint64
* @description First epoch from which this transfer shall be paid.
*/
readonly startEpoch?: string;
};
readonly vegaScalarValue: { readonly vegaScalarValue: {
readonly value?: string; readonly value?: string;
}; };
@@ -1713,15 +1442,6 @@ export interface components {
*/ */
readonly probabilityOfTrading?: number; readonly probabilityOfTrading?: number;
}; };
/** Spot product configuration */
readonly vegaSpotProduct: {
/** @description Base asset ID. */
readonly baseAsset?: string;
/** @description Product name. */
readonly name?: string;
/** @description Quote asset ID. */
readonly quoteAsset?: string;
};
readonly vegaStakeDeposited: { readonly vegaStakeDeposited: {
/** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */ /** @description Amount deposited as an unsigned base 10 integer scaled to the asset's decimal places. */
readonly amount?: string; readonly amount?: string;
@@ -1787,13 +1507,6 @@ export interface components {
readonly scalarVal?: components['schemas']['vegaScalarValue']; readonly scalarVal?: components['schemas']['vegaScalarValue'];
readonly vectorVal?: components['schemas']['vegaVectorValue']; readonly vectorVal?: components['schemas']['vegaVectorValue'];
}; };
/** @description Configuration required to turn a new market proposal in to a successor market proposal. */
readonly vegaSuccessorConfiguration: {
/** @description A decimal value between or equal to 0 and 1, specifying the fraction of the insurance pool balance that is carried over from the parent market to the successor. */
readonly insurancePoolFraction?: string;
/** @description ID of the market that the successor should take over from. */
readonly parentMarketId?: string;
};
/** TargetStakeParameters contains parameters used in target stake calculation */ /** TargetStakeParameters contains parameters used in target stake calculation */
readonly vegaTargetStakeParameters: { readonly vegaTargetStakeParameters: {
/** /**
@@ -1834,14 +1547,14 @@ export interface components {
}; };
/** Update an existing market on Vega */ /** Update an existing market on Vega */
readonly vegaUpdateMarket: { readonly vegaUpdateMarket: {
/** @description Updated configuration of the futures market. */ /** @description Updated configuration of the market. */
readonly changes?: components['schemas']['vegaUpdateMarketConfiguration']; readonly changes?: components['schemas']['vegaUpdateMarketConfiguration'];
/** @description Market ID the update is for. */ /** @description Market ID the update is for. */
readonly marketId?: string; readonly marketId?: string;
}; };
/** Configuration to update a futures market on Vega */ /** Configuration to update a market on Vega */
readonly vegaUpdateMarketConfiguration: { readonly vegaUpdateMarketConfiguration: {
/** @description Updated futures market instrument configuration. */ /** @description Updated market instrument configuration. */
readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration']; readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration'];
/** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */ /** @description Linear slippage factor is used to cap the slippage component of maintenance margin - it is applied to the slippage volume. */
readonly linearSlippageFactor?: string; readonly linearSlippageFactor?: string;
@@ -1854,7 +1567,7 @@ export interface components {
* price levels over which automated liquidity provision orders will be deployed. * price levels over which automated liquidity provision orders will be deployed.
*/ */
readonly lpPriceRange?: string; readonly lpPriceRange?: string;
/** @description Optional futures market metadata, tags. */ /** @description Optional market metadata, tags. */
readonly metadata?: readonly string[]; readonly metadata?: readonly string[];
/** @description Price monitoring parameters. */ /** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters']; readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
@@ -1868,26 +1581,6 @@ export interface components {
/** @description The network parameter to update. */ /** @description The network parameter to update. */
readonly changes?: components['schemas']['vegaNetworkParameter']; readonly changes?: components['schemas']['vegaNetworkParameter'];
}; };
/** Update an existing spot market on Vega */
readonly vegaUpdateSpotMarket: {
/** @description Updated configuration of the spot market. */
readonly changes?: components['schemas']['vegaUpdateSpotMarketConfiguration'];
/** @description Market ID the update is for. */
readonly marketId?: string;
};
/** Configuration to update a spot market on Vega */
readonly vegaUpdateSpotMarketConfiguration: {
/** @description Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected. */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/** @description Optional spot market metadata, tags. */
readonly metadata?: readonly string[];
/** @description Price monitoring parameters. */
readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters'];
/** @description Simple risk model parameters, valid only if MODEL_SIMPLE is selected. */
readonly simple?: components['schemas']['vegaSimpleModelParams'];
/** @description Specifies parameters related to target stake calculation. */
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
};
readonly vegaVectorValue: { readonly vegaVectorValue: {
readonly value?: readonly string[]; readonly value?: readonly string[];
}; };
@@ -1916,12 +1609,12 @@ export interface components {
export type external = Record<string, never>; export type external = Record<string, never>;
export interface operations { export interface operations {
/**
* Info
* @description Get information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
*/
BlockExplorer_Info: { BlockExplorer_Info: {
/**
* Info
* @description Get information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built
*/
responses: { responses: {
/** @description A successful response. */ /** @description A successful response. */
200: { 200: {
@@ -1937,38 +1630,19 @@ export interface operations {
}; };
}; };
}; };
/**
* List transactions
* @description List transactions from the Vega blockchain
*/
BlockExplorer_ListTransactions: { BlockExplorer_ListTransactions: {
parameters: { /**
query?: { * List transactions
/** * @description List transactions from the Vega blockchain
* @description Number of transactions to be returned from the blockchain. */
* This is deprecated, use first and last instead. parameters?: {
*/ /** @description Number of transactions to be returned from the blockchain. */
/** @description Optional cursor to paginate the request. */
/** @description Optional cursor to paginate the request. */
readonly query?: {
limit?: number; limit?: number;
/** @description Optional cursor to paginate the request. */
before?: string; before?: string;
/** @description Optional cursor to paginate the request. */
after?: string; after?: string;
/** @description Transaction command types filter, for listing transactions with specified command types. */
cmdTypes?: readonly string[];
/** @description Transaction command types exclusion filter, for listing all the transactions except the ones with specified command types. */
excludeCmdTypes?: readonly string[];
/** @description Party IDs filter, can be sender or receiver. */
parties?: readonly string[];
/**
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `after` cursor to paginate forwards.
* On its own, this will return the first `first` transactions.
*/
first?: number;
/**
* @description Number of transactions to be returned from the blockchain. Use in conjunction with the `before` cursor to paginate backwards.
* On its own, this will return the last `last` transactions.
*/
last?: number;
}; };
}; };
responses: { responses: {
@@ -1986,14 +1660,14 @@ export interface operations {
}; };
}; };
}; };
/**
* Get transaction
* @description Get a transaction from the Vega blockchain
*/
BlockExplorer_GetTransaction: { BlockExplorer_GetTransaction: {
/**
* Get transaction
* @description Get a transaction from the Vega blockchain
*/
parameters: { parameters: {
path: { /** @description Hash of the transaction */
/** @description Hash of the transaction */ readonly path: {
hash: string; hash: string;
}; };
}; };
+1 -1
View File
@@ -1,5 +1,5 @@
const { join } = require('path'); const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind'); const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme'); const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes'); const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
+2 -2
View File
@@ -5,8 +5,8 @@
"types": ["node"] "types": ["node"]
}, },
"files": [ "files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts" "../../node_modules/@nrwl/react/typings/image.d.ts"
], ],
"exclude": [ "exclude": [
"**/*.spec.ts", "**/*.spec.ts",
+2 -2
View File
@@ -18,7 +18,7 @@
"jest.config.ts" "jest.config.ts"
], ],
"files": [ "files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts" "../../node_modules/@nrwl/react/typings/image.d.ts"
] ]
} }
+2 -5
View File
@@ -1,8 +1,6 @@
const { composePlugins, withNx } = require('@nx/webpack');
const { withReact } = require('@nx/react');
const SentryPlugin = require('@sentry/webpack-plugin'); const SentryPlugin = require('@sentry/webpack-plugin');
module.exports = composePlugins(withNx(), withReact(), (config) => { module.exports = (config, context) => {
const additionalPlugins = process.env.SENTRY_AUTH_TOKEN const additionalPlugins = process.env.SENTRY_AUTH_TOKEN
? [ ? [
new SentryPlugin({ new SentryPlugin({
@@ -15,6 +13,5 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
return { return {
...config, ...config,
plugins: [...additionalPlugins, ...config.plugins], plugins: [...additionalPlugins, ...config.plugins],
ignoreWarnings: [/Failed to parse source map/],
}; };
}); };
+1 -1
View File
@@ -49,7 +49,7 @@ module.exports = defineConfig({
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7', vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de', vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
txTimeout: { timeout: 70000 }, txTimeout: { timeout: 70000 },
epochTimeout: { timeout: 12000 }, epochTimeout: { timeout: 10000 },
blockConfirmations: 3, blockConfirmations: 3,
grepTags: '@regression @smoke @slow', grepTags: '@regression @smoke @slow',
grepFilterSpecs: true, grepFilterSpecs: true,
+3 -4
View File
@@ -1,11 +1,10 @@
{ {
"name": "governance-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json", "$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/governance-e2e/src", "sourceRoot": "apps/governance-e2e/src",
"projectType": "application", "projectType": "application",
"targets": { "targets": {
"e2e": { "e2e": {
"executor": "@nx/cypress:cypress", "executor": "@nrwl/cypress:cypress",
"options": { "options": {
"cypressConfig": "apps/governance-e2e/cypress.config.js", "cypressConfig": "apps/governance-e2e/cypress.config.js",
"devServerTarget": "governance:serve" "devServerTarget": "governance:serve"
@@ -17,14 +16,14 @@
} }
}, },
"lint": { "lint": {
"executor": "@nx/linter:eslint", "executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"], "outputs": ["{options.outputFile}"],
"options": { "options": {
"lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"] "lintFilePatterns": ["apps/governance-e2e/**/*.{js,ts}"]
} }
}, },
"build": { "build": {
"executor": "nx:run-commands", "executor": "@nrwl/workspace:run-commands",
"outputs": [], "outputs": [],
"options": { "options": {
"command": "yarn tsc --project ./apps/governance-e2e/" "command": "yarn tsc --project ./apps/governance-e2e/"
@@ -1,63 +0,0 @@
export const previousEpochData = {
epoch: {
id: '7611',
validatorsConnection: {
edges: [
{
node: {
id: 'cd96782bc0ad5679869cf69fe7838a92212da7f53b4a214bed68067117494122',
stakedTotal: '3154229668720612941799',
rewardScore: {
rawValidatorScore: '0.2',
performanceScore: '1',
multisigScore: '0',
validatorScore: '0.2',
normalisedScore: '0.2007216887087119',
validatorStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RewardScore',
},
rankingScore: {
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
previousStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
rankingScore: '0.211713765544955625',
stakeScore: '0.2016321576618625',
performanceScore: '1',
votingPower: '2007',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
{
node: {
id: '887d936f797a47032eceb572a13b69b581d3b1fa595a7d021a3e3cf2a5d2acfd',
stakedTotal: '3151161904761904764551',
rewardScore: {
rawValidatorScore: '0.2',
performanceScore: '1',
multisigScore: '1',
validatorScore: '0.2',
normalisedScore: '0.2007216887087119',
validatorStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
__typename: 'RewardScore',
},
rankingScore: {
status: 'VALIDATOR_NODE_STATUS_TENDERMINT',
previousStatus: 'VALIDATOR_NODE_STATUS_TENDERMINT',
rankingScore: '0.211507855409133255',
stakeScore: '0.2014360527706031',
performanceScore: '1',
votingPower: '2007',
__typename: 'RankingScore',
},
__typename: 'Node',
},
__typename: 'NodeEdge',
},
],
__typename: 'NodesConnection',
},
__typename: 'Epoch',
},
};
@@ -28,17 +28,18 @@ import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils'; import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
const proposalVoteProgressForPercentage = const proposalVoteProgressForPercentage =
'vote-progress-indicator-percentage-for'; '[data-testid="vote-progress-indicator-percentage-for"]';
const proposalVoteProgressAgainstPercentage = const proposalVoteProgressAgainstPercentage =
'vote-progress-indicator-percentage-against'; '[data-testid="vote-progress-indicator-percentage-against"]';
const proposalVoteProgressForTokens = 'vote-progress-indicator-tokens-for'; const proposalVoteProgressForTokens =
'[data-testid="vote-progress-indicator-tokens-for"]';
const proposalVoteProgressAgainstTokens = const proposalVoteProgressAgainstTokens =
'vote-progress-indicator-tokens-against'; '[data-testid="vote-progress-indicator-tokens-against"]';
const changeVoteButton = 'change-vote-button'; const changeVoteButton = '[data-testid="change-vote-button"]';
const proposalDetailsTitle = 'proposal-title'; const proposalDetailsTitle = '[data-testid="proposal-title"]';
const proposalDetailsDescription = 'proposal-description'; const proposalDetailsDescription = '[data-testid="proposal-description"]';
const openProposals = 'open-proposals'; const openProposals = '[data-testid="open-proposals"]';
const viewProposalButton = 'view-proposal-btn'; const viewProposalButton = '[data-testid="view-proposal-btn"]';
const proposalDescriptionToggle = 'proposal-description-toggle'; const proposalDescriptionToggle = 'proposal-description-toggle';
const voteBreakdownToggle = 'vote-breakdown-toggle'; const voteBreakdownToggle = 'vote-breakdown-toggle';
const proposalTermsToggle = 'proposal-json-toggle'; const proposalTermsToggle = 'proposal-json-toggle';
@@ -71,18 +72,18 @@ describe(
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
cy.getByTestId(openProposals).within(() => { cy.get(openProposals).within(() => {
getProposalFromTitle(rawProposal.rationale.title).within(() => { getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.getByTestId(viewProposalButton).should('be.visible').click(); cy.get(viewProposalButton).should('be.visible').click();
}); });
}); });
cy.getByTestId(proposalDetailsTitle).should( cy.get(proposalDetailsTitle).should(
'contain.text', 'contain.text',
rawProposal.rationale.title rawProposal.rationale.title
); );
cy.getByTestId(proposalDescriptionToggle).click(); cy.getByTestId(proposalDescriptionToggle).click();
cy.getByTestId('proposal-description-toggle'); cy.getByTestId('proposal-description-toggle');
cy.getByTestId(proposalDetailsDescription) cy.get(proposalDetailsDescription)
.find('p') .find('p')
.should('have.text', proposalDescription); .should('have.text', proposalDescription);
}); });
@@ -116,7 +117,7 @@ describe(
}); });
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => getProposalFromTitle(proposalTitle).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
cy.wrap( cy.wrap(
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000)) formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
@@ -138,7 +139,7 @@ describe(
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
}); });
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should( cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
@@ -165,7 +166,7 @@ describe(
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
}); });
// 3001-VOTE-080 // 3001-VOTE-080
@@ -182,16 +183,14 @@ describe(
.contains(votedDate) .contains(votedDate)
.should('be.visible'); .should('be.visible');
}); });
cy.getByTestId(proposalVoteProgressForPercentage) // 3001-VOTE-072 cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
.contains('100.00%') .contains('100.00%')
.and('be.visible'); .and('be.visible');
cy.getByTestId(proposalVoteProgressAgainstPercentage) cy.get(proposalVoteProgressAgainstPercentage)
.contains('0.00%') .contains('0.00%')
.and('be.visible'); .and('be.visible');
cy.getByTestId(proposalVoteProgressForTokens) cy.get(proposalVoteProgressForTokens).contains('1.00').and('be.visible');
.contains('1.00') cy.get(proposalVoteProgressAgainstTokens)
.and('be.visible');
cy.getByTestId(proposalVoteProgressAgainstTokens)
.contains('0.00') .contains('0.00')
.and('be.visible'); .and('be.visible');
cy.getByTestId(voteBreakdownToggle).click(); cy.getByTestId(voteBreakdownToggle).click();
@@ -212,15 +211,15 @@ describe(
getProposalInformationFromTable('Number of voting parties') getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1') .should('have.text', '1')
.and('be.visible'); .and('be.visible');
cy.getByTestId(changeVoteButton).should('be.visible').click(); cy.get(changeVoteButton).should('be.visible').click();
voteForProposal('for'); voteForProposal('for');
// 3001-VOTE-064 // 3001-VOTE-064
getProposalInformationFromTable('Tokens for proposal') getProposalInformationFromTable('Tokens for proposal')
.should('have.text', (1).toFixed(2)) .should('have.text', (1).toFixed(2))
.and('be.visible'); .and('be.visible');
cy.getByTestId(changeVoteButton).should('be.visible').click(); cy.get(changeVoteButton).should('be.visible').click();
voteForProposal('against'); voteForProposal('against');
cy.getByTestId(proposalVoteProgressAgainstPercentage) cy.get(proposalVoteProgressAgainstPercentage)
.contains('100.00%') .contains('100.00%')
.and('be.visible'); .and('be.visible');
getProposalInformationFromTable('Tokens against proposal') getProposalInformationFromTable('Tokens against proposal')
@@ -237,15 +236,13 @@ describe(
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
}); });
voteForProposal('for'); voteForProposal('for');
// 3001-VOTE-079 // 3001-VOTE-079
cy.contains('You voted: For').should('be.visible'); cy.contains('You voted: For').should('be.visible');
cy.getByTestId(proposalVoteProgressForTokens) cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
.contains('1')
.and('be.visible');
cy.getByTestId(voteBreakdownToggle).click(); cy.getByTestId(voteBreakdownToggle).click();
getProposalInformationFromTable('Total Supply') getProposalInformationFromTable('Total Supply')
.invoke('text') .invoke('text')
@@ -261,22 +258,22 @@ describe(
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
}); });
cy.getByTestId(proposalVoteProgressForPercentage) cy.get(proposalVoteProgressForPercentage)
.contains('100.00%') .contains('100.00%')
.and('be.visible'); .and('be.visible');
cy.getByTestId(proposalVoteProgressAgainstPercentage) cy.get(proposalVoteProgressAgainstPercentage)
.contains('0.00%') .contains('0.00%')
.and('be.visible'); .and('be.visible');
// 3001-VOTE-065 // 3001-VOTE-065
cy.getByTestId(changeVoteButton).should('be.visible').click(); cy.get(changeVoteButton).should('be.visible').click();
voteForProposal('for'); voteForProposal('for');
cy.getByTestId(proposalVoteProgressForTokens) cy.get(proposalVoteProgressForTokens)
.contains(tokensRequiredToAchieveResult) .contains(tokensRequiredToAchieveResult)
.and('be.visible'); .and('be.visible');
cy.getByTestId(proposalVoteProgressAgainstTokens) cy.get(proposalVoteProgressAgainstTokens)
.contains('0.00') .contains('0.00')
.and('be.visible'); .and('be.visible');
cy.getByTestId(voteBreakdownToggle).click(); cy.getByTestId(voteBreakdownToggle).click();
@@ -313,7 +310,7 @@ describe(
createRawProposal(); createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
voteForProposal('for'); voteForProposal('for');
cy.contains('You voted: For').should('be.visible'); cy.contains('You voted: For').should('be.visible');
@@ -322,16 +319,13 @@ describe(
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
cy.getByTestId('you-voted').should('not.exist'); cy.getByTestId('you-voted').should('not.exist');
voteForProposal('against'); voteForProposal('against');
cy.contains('You voted: Against').should('be.visible'); cy.contains('You voted: Against').should('be.visible');
switchVegaWalletPubKey(); switchVegaWalletPubKey();
cy.getByTestId(proposalVoteProgressForTokens).should( cy.get(proposalVoteProgressForTokens).should('contain.text', '1.00');
'contain.text',
'1.00'
);
// Checking vote status for different public keys is displayed correctly // Checking vote status for different public keys is displayed correctly
cy.contains('You voted: For').should('be.visible'); cy.contains('You voted: For').should('be.visible');
}); });
@@ -19,13 +19,13 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions'; import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
const proposalListItem = '[data-testid="proposals-list-item"]'; const proposalListItem = '[data-testid="proposals-list-item"]';
const closedProposals = 'closed-proposals'; const closedProposals = '[data-testid="closed-proposals"]';
const proposalStatus = 'proposal-status'; const proposalStatus = '[data-testid="proposal-status"]';
const viewProposalButton = 'view-proposal-btn'; const viewProposalButton = '[data-testid="view-proposal-btn"]';
const votesTable = 'votes-table'; const votesTable = '[data-testid="votes-table"]';
const openProposals = 'open-proposals'; const openProposals = '[data-testid="open-proposals"]';
const proposalVoteProgressForPercentage = const proposalVoteProgressForPercentage =
'vote-progress-indicator-percentage-for'; '[data-testid="vote-progress-indicator-percentage-for"]';
const proposalTimeout = { timeout: 8000 }; const proposalTimeout = { timeout: 8000 };
context( context(
@@ -55,18 +55,18 @@ context(
cy.createMarket(); cy.createMarket();
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.getByTestId(closedProposals).within(() => { cy.get(closedProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last() .last()
.within(() => { .within(() => {
cy.getByTestId(proposalStatus).should('have.text', 'Enacted'); cy.get(proposalStatus).should('have.text', 'Enacted');
cy.getByTestId(viewProposalButton).click(); cy.get(viewProposalButton).click();
}); });
}); });
cy.getByTestId('proposal-type').should('have.text', 'New market'); cy.getByTestId('proposal-type').should('have.text', 'New market');
cy.getByTestId(proposalStatus).should('have.text', 'Enacted'); cy.get(proposalStatus).should('have.text', 'Enacted');
cy.getByTestId(votesTable).within(() => { cy.get(votesTable).within(() => {
cy.contains('Vote passed.').should('be.visible'); cy.contains('Vote passed.').should('be.visible');
cy.contains('Voting has ended.').should('be.visible'); cy.contains('Voting has ended.').should('be.visible');
}); });
@@ -81,27 +81,21 @@ context(
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.getByTestId(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last() .last()
.within(() => cy.getByTestId(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
cy.getByTestId(proposalStatus).should('have.text', 'Open'); cy.get(proposalStatus).should('have.text', 'Open');
voteForProposal('for'); voteForProposal('for');
cy.getByTestId(proposalStatus, proposalTimeout) cy.get(proposalStatus, proposalTimeout).should('have.text', 'Passed');
.should('have.text', 'Passed') cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
.then(() => { cy.get(votesTable).within(() => {
cy.getByTestId(proposalStatus, proposalTimeout).should(
'have.text',
'Enacted'
);
});
cy.getByTestId(votesTable).within(() => {
cy.contains('Vote passed.').should('be.visible'); cy.contains('Vote passed.').should('be.visible');
cy.contains('Voting has ended.').should('be.visible'); cy.contains('Voting has ended.').should('be.visible');
}); });
cy.getByTestId(proposalVoteProgressForPercentage) cy.get(proposalVoteProgressForPercentage)
.contains('100.00%') .contains('100.00%')
.and('be.visible'); .and('be.visible');
}); });
@@ -115,18 +109,15 @@ context(
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.getByTestId(openProposals, { timeout: 6000 }).within(() => { cy.get(openProposals, { timeout: 6000 }).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last() .last()
.within(() => cy.getByTestId(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
cy.getByTestId(proposalStatus).should('have.text', 'Open'); cy.get(proposalStatus).should('have.text', 'Open');
voteForProposal('for'); voteForProposal('for');
cy.getByTestId(proposalStatus, proposalTimeout).should( cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
'have.text',
'Enacted'
);
}); });
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050 // 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
@@ -137,17 +128,14 @@ context(
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.reload(); cy.reload();
waitForSpinner(); waitForSpinner();
cy.getByTestId(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.contains(proposalTitle) cy.contains(proposalTitle)
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last() .last()
.within(() => cy.getByTestId(viewProposalButton).click()); .within(() => cy.get(viewProposalButton).click());
}); });
cy.getByTestId(proposalStatus).should('have.text', 'Open'); cy.get(proposalStatus).should('have.text', 'Open');
cy.getByTestId(proposalStatus, proposalTimeout).should( cy.get(proposalStatus, proposalTimeout).should('have.text', 'Declined');
'have.text',
'Declined'
);
getProposalInformationFromTable('Rejection reason') getProposalInformationFromTable('Rejection reason')
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED') .contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
.and('be.visible'); .and('be.visible');
@@ -36,19 +36,20 @@ import {
import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import type { testFreeformProposal } from '../../support/common-interfaces'; import type { testFreeformProposal } from '../../support/common-interfaces';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators'; const vegaWalletStakedBalances =
const vegaWalletAssociatedBalance = 'associated-amount'; '[data-testid="vega-wallet-balance-staked-validators"]';
const vegaWalletNameElement = 'wallet-name'; const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
const vegaWallet = 'vega-wallet'; const vegaWalletNameElement = '[data-testid="wallet-name"]';
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn'; const vegaWallet = '[data-testid="vega-wallet"]';
const newProposalSubmitButton = 'proposal-submit'; const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
const viewProposalButton = 'view-proposal-btn'; const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const rawProposalData = 'proposal-data'; const viewProposalButton = '[data-testid="view-proposal-btn"]';
const voteButtons = 'vote-buttons'; const rawProposalData = '[data-testid="proposal-data"]';
const voteButtons = '[data-testid="vote-buttons"]';
const rejectProposalsLink = '[href="/proposals/rejected"]'; const rejectProposalsLink = '[href="/proposals/rejected"]';
const feedbackError = 'Error'; const feedbackError = '[data-testid="Error"]';
const noOpenProposals = 'no-open-proposals'; const noOpenProposals = '[data-testid="no-open-proposals"]';
const noClosedProposals = 'no-closed-proposals'; const noClosedProposals = '[data-testid="no-closed-proposals"]';
const txTimeout = Cypress.env('txTimeout'); const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout'); const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 }; const proposalTimeout = { timeout: 14000 };
@@ -92,10 +93,10 @@ context(
// Test can only pass if run before other proposal tests. // Test can only pass if run before other proposal tests.
it.skip('Should be able to see that no proposals exist', function () { it.skip('Should be able to see that no proposals exist', function () {
// 3001-VOTE-003 // 3001-VOTE-003
cy.getByTestId(noOpenProposals) cy.get(noOpenProposals)
.should('be.visible') .should('be.visible')
.and('have.text', 'There are no open or yet to enact proposals'); .and('have.text', 'There are no open or yet to enact proposals');
cy.getByTestId(noClosedProposals) cy.get(noClosedProposals)
.should('be.visible') .should('be.visible')
.and('have.text', 'There are no enacted or rejected proposals'); .and('have.text', 'There are no enacted or rejected proposals');
}); });
@@ -125,14 +126,11 @@ context(
stakingValidatorPageAddStake('2'); stakingValidatorPageAddStake('2');
closeStakingDialog(); closeStakingDialog();
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should( cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
'contain',
'2'
);
createRawProposal(); createRawProposal();
}); });
it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () { it.skip('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM); goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle()); enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
cy.get('input:invalid') cy.get('input:invalid')
@@ -140,7 +138,7 @@ context(
.should('equal', 'Value must be greater than or equal to 1.'); .should('equal', 'Value must be greater than or equal to 1.');
}); });
it('Creating a proposal - proposal rejected - when closing time later than system default', function () { it.skip('Creating a proposal - proposal rejected - when closing time later than system default', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM); goToMakeNewProposal(governanceProposalType.FREEFORM);
enterUniqueFreeFormProposalBody( enterUniqueFreeFormProposalBody(
'100000', '100000',
@@ -170,7 +168,7 @@ context(
getProposalFromTitle(rawProposal.rationale.title).within(() => { getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.contains('Rejected').should('be.visible'); cy.contains('Rejected').should('be.visible');
cy.contains('Close time too late').should('be.visible'); cy.contains('Close time too late').should('be.visible');
cy.getByTestId(viewProposalButton).click(); cy.get(viewProposalButton).click();
}); });
}); });
cy.getByTestId('proposal-status').should('have.text', 'Rejected'); cy.getByTestId('proposal-status').should('have.text', 'Rejected');
@@ -187,14 +185,14 @@ context(
const errorMsg = const errorMsg =
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'; 'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)';
vegaWalletTeardown(); vegaWalletTeardown();
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains( cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
'0.00', '0.00',
txTimeout txTimeout
); );
goToMakeNewProposal(governanceProposalType.RAW); goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8)); enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.getByTestId(feedbackError).should('have.text', errorMsg); cy.get(feedbackError).should('have.text', errorMsg);
closeDialog(); closeDialog();
}); });
@@ -207,7 +205,7 @@ context(
goToMakeNewProposal(governanceProposalType.RAW); goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8)); enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.getByTestId(feedbackError).should('have.text', errorMsg); cy.get(feedbackError).should('have.text', errorMsg);
closeDialog(); closeDialog();
}); });
@@ -223,17 +221,17 @@ context(
createTenDigitUnixTimeStampForSpecifiedDays(8); createTenDigitUnixTimeStampForSpecifiedDays(8);
freeformProposal.unexpected = `i shouldn't be here`; freeformProposal.unexpected = `i shouldn't be here`;
const proposalPayload = JSON.stringify(freeformProposal); const proposalPayload = JSON.stringify(freeformProposal);
cy.getByTestId(rawProposalData).type(proposalPayload, { cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.getByTestId(feedbackError).should('have.text', errorMsg); cy.get(feedbackError).should('have.text', errorMsg);
closeDialog(); closeDialog();
cy.getByTestId(rawProposalData) cy.get(rawProposalData)
.invoke('val') .invoke('val')
.should('contain', "i shouldn't be here"); .should('contain', "i shouldn't be here");
}); });
@@ -251,15 +249,15 @@ context(
rawProposal.terms.unexpectedField = `i shouldn't be here`; rawProposal.terms.unexpectedField = `i shouldn't be here`;
const proposalPayload = JSON.stringify(rawProposal); const proposalPayload = JSON.stringify(rawProposal);
cy.getByTestId(rawProposalData).type(proposalPayload, { cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.getByTestId(feedbackError).should('have.text', errorMsg); cy.get(feedbackError).should('have.text', errorMsg);
closeDialog(); closeDialog();
}); });
@@ -267,10 +265,10 @@ context(
// 3006-PASC-006 3006-PASC-007 3008-PFRO-018 3008-PFRO-019 3003-PMAN-006 3003-PMAN-007 // 3006-PASC-006 3006-PASC-007 3008-PFRO-018 3008-PFRO-019 3003-PMAN-006 3003-PMAN-007
it('Unable to submit proposal without valid json', function () { it('Unable to submit proposal without valid json', function () {
goToMakeNewProposal(governanceProposalType.RAW); goToMakeNewProposal(governanceProposalType.RAW);
cy.getByTestId(newProposalSubmitButton).click(); cy.get(newProposalSubmitButton).click();
cy.getByTestId('input-error-text').should('have.text', 'Required'); cy.getByTestId('input-error-text').should('have.text', 'Required');
cy.getByTestId(rawProposalData).type('Not a valid json string'); cy.get(rawProposalData).type('Not a valid json string');
cy.getByTestId(newProposalSubmitButton).click(); cy.get(newProposalSubmitButton).click();
cy.getByTestId('input-error-text').should( cy.getByTestId('input-error-text').should(
'have.text', 'have.text',
'Must be valid JSON' 'Must be valid JSON'
@@ -285,22 +283,22 @@ context(
submitUniqueRawProposal({ proposalTitle: proposalTitle }); submitUniqueRawProposal({ proposalTitle: proposalTitle });
ethereumWalletConnect(); ethereumWalletConnect();
stakingPageDisassociateTokens('0.0001'); stakingPageDisassociateTokens('0.0001');
cy.getByTestId(vegaWallet) cy.get(vegaWallet)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain', 'contain',
'0.9999' '0.9999'
); );
}); });
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => getProposalFromTitle(proposalTitle).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
cy.contains('Vote breakdown').should('be.visible', { cy.contains('Vote breakdown').should('be.visible', {
timeout: 10000, timeout: 10000,
}); });
cy.getByTestId(voteButtons).should('not.exist'); cy.get(voteButtons).should('not.exist');
cy.getByTestId('min-proposal-requirements').should( cy.getByTestId('min-proposal-requirements').should(
'have.text', 'have.text',
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal` `You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
@@ -313,20 +311,20 @@ context(
cy.get('[data-testid="disconnect"]').click(); cy.get('[data-testid="disconnect"]').click();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.getByTestId(viewProposalButton).click() cy.get(viewProposalButton).click()
); );
}); });
// 3001-VOTE-075 // 3001-VOTE-075
// 3001-VOTE-076 // 3001-VOTE-076
cy.getByTestId(connectToVegaWalletButton) cy.get(connectToVegaWalletButton)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Vega wallet') .and('have.text', 'Connect Vega wallet')
.click(); .click();
cy.getByTestId('connector-jsonRpc').click(); cy.getByTestId('connector-jsonRpc').click();
cy.getByTestId(vegaWalletNameElement).should('be.visible'); cy.get(vegaWalletNameElement).should('be.visible');
cy.getByTestId(connectToVegaWalletButton).should('not.exist'); cy.get(connectToVegaWalletButton).should('not.exist');
// 3001-VOTE-100 // 3001-VOTE-100
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains( cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
'1.00', '1.00',
txTimeout txTimeout
); );
@@ -8,7 +8,6 @@ import {
} from '../../support/common.functions'; } from '../../support/common.functions';
import { import {
getDownloadedProposalJsonPath, getDownloadedProposalJsonPath,
getProposalFromTitle,
submitUniqueRawProposal, submitUniqueRawProposal,
} from '../../support/governance.functions'; } from '../../support/governance.functions';
import { import {
@@ -31,31 +30,32 @@ import {
} from '../../support/wallet-functions'; } from '../../support/wallet-functions';
const proposalListItem = '[data-testid="proposals-list-item"]'; const proposalListItem = '[data-testid="proposals-list-item"]';
const openProposals = 'open-proposals'; const openProposals = '[data-testid="open-proposals"]';
const proposalType = 'proposal-type'; const proposalType = '[data-testid="proposal-type"]';
const proposalDetails = 'proposal-details'; const proposalDetails = '[data-testid="proposal-details"]';
const newProposalSubmitButton = 'proposal-submit'; const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const proposalVoteDeadline = 'proposal-vote-deadline'; const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
const proposalParameterSelect = 'proposal-parameter-select'; const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
const proposalMarketSelect = 'proposal-market-select'; const proposalMarketSelect = '[data-testid="proposal-market-select"]';
const newProposalTitle = 'proposal-title'; const newProposalTitle = '[data-testid="proposal-title"]';
const newProposalDescription = 'proposal-description'; const newProposalDescription = '[data-testid="proposal-description"]';
const newProposalTerms = 'proposal-terms'; const newProposalTerms = '[data-testid="proposal-terms"]';
const newProposedParameterValue = 'selected-proposal-param-new-value'; const newProposedParameterValue =
const minVoteDeadline = 'min-vote'; '[data-testid="selected-proposal-param-new-value"]';
const maxVoteDeadline = 'max-vote'; const minVoteDeadline = '[data-testid="min-vote"]';
const minValidationDeadline = 'min-validation'; const maxVoteDeadline = '[data-testid="max-vote"]';
const minEnactDeadline = 'min-enactment'; const minValidationDeadline = '[data-testid="min-validation"]';
const maxEnactDeadline = 'max-enactment'; const minEnactDeadline = '[data-testid="min-enactment"]';
const inputError = 'input-error-text'; const maxEnactDeadline = '[data-testid="max-enactment"]';
const enactmentDeadlineError = 'enactment-before-voting-deadline'; const inputError = '[data-testid="input-error-text"]';
const proposalDownloadBtn = 'proposal-download-json'; const enactmentDeadlineError =
'[data-testid="enactment-before-voting-deadline"]';
const proposalDownloadBtn = '[data-testid="proposal-download-json"]';
const feedbackError = '[data-testid="Error"]'; const feedbackError = '[data-testid="Error"]';
const viewProposalBtn = 'view-proposal-btn'; const viewProposalBtn = 'view-proposal-btn';
const liquidityVoteStatus = 'liquidity-votes-status'; const liquidityVoteStatus = 'liquidity-votes-status';
const tokenVoteStatus = 'token-votes-status'; const tokenVoteStatus = 'token-votes-status';
const proposalJsonToggle = 'proposal-json-toggle'; const proposalTermsSection = 'proposal';
const proposalJsonSection = 'proposal-json';
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey'); const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
const fUSDCId = const fUSDCId =
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc'; '816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
@@ -86,20 +86,18 @@ context(
it('Unable to submit network parameter with missing/invalid fields', function () { it('Unable to submit network parameter with missing/invalid fields', function () {
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.getByTestId(proposalDownloadBtn).click(); cy.get(proposalDownloadBtn).click();
cy.getByTestId(inputError).should('have.length', 3); cy.get(inputError).should('have.length', 3);
cy.getByTestId(newProposalTitle).type( cy.get(newProposalTitle).type(
'Invalid update network parameter proposal' 'Invalid update network parameter proposal'
); );
cy.getByTestId(newProposalDescription).type( cy.get(newProposalDescription).type('E2E invalid test for proposals');
'E2E invalid test for proposals' cy.get(proposalParameterSelect).select(
);
cy.getByTestId(proposalParameterSelect).select(
'spam_protection_proposal_min_tokens' 'spam_protection_proposal_min_tokens'
); );
cy.getByTestId(newProposedParameterValue).type('0'); cy.get(newProposedParameterValue).type('0');
cy.getByTestId(proposalVoteDeadline).clear().type('0'); cy.get(proposalVoteDeadline).clear().type('0');
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.click() .click()
.then(() => { .then(() => {
cy.wrap( cy.wrap(
@@ -109,7 +107,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); submitUniqueRawProposal({ proposalBody: filePath, submit: false });
}); });
}); });
cy.getByTestId(newProposalSubmitButton).click(); cy.get(newProposalSubmitButton).click();
validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON'); validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON');
}); });
@@ -117,33 +115,29 @@ context(
it('Able to download and submit network param proposal', function () { it('Able to download and submit network param proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
// 3007-PNEC-006 // 3007-PNEC-006
cy.getByTestId(newProposalTitle) cy.get(newProposalTitle)
.siblings() .siblings()
.should('contain.text', '(100 characters or less)'); .should('contain.text', '(100 characters or less)');
// 3007-PNEC-004 3007-PNEC-005 // 3007-PNEC-004 3007-PNEC-005
cy.getByTestId(newProposalTitle).type( cy.get(newProposalTitle).type('Test update network parameter proposal');
'Test update network parameter proposal'
);
// 3007-PNEC-009 // 3007-PNEC-009
cy.getByTestId(newProposalDescription) cy.get(newProposalDescription)
.siblings() .siblings()
.should('contain.text', '(20,000 characters or less)'); .should('contain.text', '(20,000 characters or less)');
// 3007-PNEC-007 3007-PNEC-008 // 3007-PNEC-007 3007-PNEC-008
cy.getByTestId(newProposalDescription).type( cy.get(newProposalDescription).type('E2E test for downloading proposals');
'E2E test for downloading proposals'
);
// 3007-PNEC-010 // 3007-PNEC-010
cy.getByTestId(proposalParameterSelect).select( cy.get(proposalParameterSelect).select(
'governance_proposal_asset_minClose' 'governance_proposal_asset_minClose'
); );
// 3007-PNEC-011 // 3007-PNEC-011
cy.getByTestId(newProposedParameterValue).type('10s'); cy.get(newProposedParameterValue).type('10s');
// 3007-PNEC-012 // 3007-PNEC-012
cy.getByTestId(proposalVoteDeadline).clear().type('2'); cy.get(proposalVoteDeadline).clear().type('2');
// 3007-PNEC-013 3007-PNEC-014 // 3007-PNEC-013 3007-PNEC-014
cy.getByTestId('voting-date').invoke('text').should('not.be.empty'); cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
// 3007-PNEC-015 // 3007-PNEC-015
cy.getByTestId(maxEnactDeadline).click(); cy.get(maxEnactDeadline).click();
// 3007-PNEC-016 // 3007-PNEC-016
cy.getByTestId('enactment-date').invoke('text').should('not.be.empty'); cy.getByTestId('enactment-date').invoke('text').should('not.be.empty');
// 3007-PNEC-017 // 3007-PNEC-017
@@ -152,7 +146,7 @@ context(
).should('be.visible'); ).should('be.visible');
// 3007-PNE-018 // 3007-PNE-018
cy.log('Download updated proposal file'); cy.log('Download updated proposal file');
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -182,21 +176,19 @@ context(
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () { it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.getByTestId(newProposalTitle).type( cy.get(newProposalTitle).type('Test update network parameter proposal');
'Test update network parameter proposal' cy.get(newProposalDescription).type('invalid deadlines');
); cy.get(proposalParameterSelect).select(
cy.getByTestId(newProposalDescription).type('invalid deadlines');
cy.getByTestId(proposalParameterSelect).select(
'spam_protection_proposal_min_tokens' 'spam_protection_proposal_min_tokens'
); );
cy.getByTestId(newProposedParameterValue).type('0'); cy.get(newProposedParameterValue).type('0');
cy.getByTestId(proposalVoteDeadline).clear().type('0'); cy.get(proposalVoteDeadline).clear().type('0');
cy.getByTestId(maxVoteDeadline).click(); cy.get(maxVoteDeadline).click();
cy.getByTestId(enactmentDeadlineError).should( cy.get(enactmentDeadlineError).should(
'have.text', 'have.text',
'The proposal will fail if enactment is earlier than the voting deadline' 'Proposal will fail if enactment is earlier than the voting deadline'
); );
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -207,7 +199,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); submitUniqueRawProposal({ proposalBody: filePath, submit: false });
}); });
}); });
cy.getByTestId(newProposalSubmitButton).click(); cy.get(newProposalSubmitButton).click();
validateFeedBackMsg( validateFeedBackMsg(
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)' 'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
); );
@@ -218,18 +210,17 @@ context(
'Able to submit valid new market proposal', 'Able to submit valid new market proposal',
{ tags: '@smoke' }, { tags: '@smoke' },
function () { function () {
const proposalTitle = 'Test new market proposal';
goToMakeNewProposal(governanceProposalType.NEW_MARKET); goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId(newProposalTitle).type('Test new market proposal'); cy.get(newProposalTitle).type('Test new market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals'); cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => { cy.fixture('/proposals/new-market').then((newMarketProposal) => {
const newMarketPayload = JSON.stringify(newMarketProposal); const newMarketPayload = JSON.stringify(newMarketProposal);
cy.getByTestId(newProposalTerms).type(newMarketPayload, { cy.get(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -240,23 +231,6 @@ context(
submitUniqueRawProposal({ proposalBody: filePath }); // 3003-PMAN-003 submitUniqueRawProposal({ proposalBody: filePath }); // 3003-PMAN-003
}); });
}); });
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() =>
cy.getByTestId('view-proposal-btn').click()
);
cy.getByTestId('proposal-market-data').within(() => {
cy.getByTestId('proposal-market-data-toggle').click();
cy.contains('Key details').click();
getMarketProposalDetailsFromTable('Name').should(
'have.text',
'Token test market'
);
cy.contains('Settlement asset').click();
// Settlement asset symbol
cy.getByTestId('3_value').should('have.text', 'fBTC');
cy.contains('Oracle').click();
cy.getByTestId('oracle-spec-links').should('have.attr', 'href');
});
} }
); );
@@ -265,19 +239,19 @@ context(
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket'; 'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
goToMakeNewProposal(governanceProposalType.NEW_MARKET); goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId(proposalDownloadBtn).should('be.visible').click(); cy.get(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3); cy.get(inputError).should('have.length', 3);
cy.getByTestId(newProposalTitle).type('Test new market proposal'); cy.get(newProposalTitle).type('Test new market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals'); cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => { cy.fixture('/proposals/new-market').then((newMarketProposal) => {
newMarketProposal.invalid = 'I am an invalid field'; newMarketProposal.invalid = 'I am an invalid field';
const newMarketPayload = JSON.stringify(newMarketProposal); const newMarketPayload = JSON.stringify(newMarketProposal);
cy.getByTestId(newProposalTerms).type(newMarketPayload, { cy.get(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -288,30 +262,28 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); submitUniqueRawProposal({ proposalBody: filePath, submit: false });
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
validateFeedBackMsg(errorMsg); validateFeedBackMsg(errorMsg);
}); });
// Will fail if run after 'Able to submit update market proposal and vote for proposal' // Will fail if run after 'Able to submit update market proposal and vote for proposal'
// 3002-PROP-022 // 3002-PROP-022
it.skip('Unable to submit update market proposal without equity-like share in the market', function () { it('Unable to submit update market proposal without equity-like share in the market', function () {
switchVegaWalletPubKey(); switchVegaWalletPubKey();
stakingPageAssociateTokens('1'); stakingPageAssociateTokens('1');
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.getByTestId(newProposalTitle).type( cy.get(newProposalTitle).type('Test update market proposal - rejected');
'Test update market proposal - rejected' cy.get(newProposalDescription).type('E2E test for proposals');
); cy.get(proposalMarketSelect).select('Test market 1');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => { cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, { cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -322,7 +294,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); submitUniqueRawProposal({ proposalBody: filePath, submit: false });
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Proposal rejected', proposalTimeout).should('be.visible'); cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE'); validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
closeDialog(); closeDialog();
@@ -340,19 +312,17 @@ context(
vegaWalletPublicKey vegaWalletPublicKey
); );
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.getByTestId(newProposalTitle).type( cy.get(newProposalTitle).type('Test update market proposal - rejected');
'Test update market proposal - rejected' cy.get(newProposalDescription).type('E2E test for proposals');
); cy.get(proposalMarketSelect).select('Test market 1');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => { cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, { cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -363,7 +333,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); submitUniqueRawProposal({ proposalBody: filePath, submit: false });
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible'); cy.contains('Transaction failed', proposalTimeout).should('be.visible');
validateFeedBackMsg( validateFeedBackMsg(
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)' 'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'
@@ -378,9 +348,9 @@ context(
vegaWalletPublicKey vegaWalletPublicKey
); );
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.getByTestId(newProposalTitle).type('Test update market proposal'); cy.get(newProposalTitle).type('Test update market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals'); cy.get(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1'); cy.get(proposalMarketSelect).select('Test market 1');
cy.get('[data-testid="update-market-details"]').within(() => { cy.get('[data-testid="update-market-details"]').within(() => {
cy.get('dd').eq(0).should('have.text', 'Test market 1'); cy.get('dd').eq(0).should('have.text', 'Test market 1');
cy.get('dd').eq(1).should('have.text', 'TEST.24h'); cy.get('dd').eq(1).should('have.text', 'TEST.24h');
@@ -395,12 +365,12 @@ context(
}); });
cy.fixture('/proposals/update-market').then((updateMarketProposal) => { cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal); const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, { cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -447,19 +417,19 @@ context(
it('Able to submit new asset proposal using min deadlines', function () { it('Able to submit new asset proposal using min deadlines', function () {
const proposalTitle = 'Test new asset proposal'; const proposalTitle = 'Test new asset proposal';
goToMakeNewProposal(governanceProposalType.NEW_ASSET); goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.getByTestId(newProposalTitle).type(proposalTitle); cy.get(newProposalTitle).type(proposalTitle);
cy.getByTestId(newProposalDescription).type('E2E test for proposals'); cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-asset').then((newAssetProposal) => { cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
const newAssetPayload = JSON.stringify(newAssetProposal); const newAssetPayload = JSON.stringify(newAssetProposal);
cy.getByTestId(newProposalTerms).type(newAssetPayload, { cy.get(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
cy.getByTestId(minVoteDeadline).click(); cy.get(minVoteDeadline).click();
cy.getByTestId(minValidationDeadline).click(); cy.get(minValidationDeadline).click();
cy.getByTestId(minEnactDeadline).click(); cy.get(minEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -470,9 +440,9 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003 submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003
}); });
}); });
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
closeDialog(); closeDialog();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click(); cy.get(newProposalSubmitButton).should('be.visible').click();
// cannot submit a proposal with ERC20 address already in use // cannot submit a proposal with ERC20 address already in use
cy.contains('Proposal rejected', proposalTimeout).should('be.visible'); cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'); validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE');
@@ -484,8 +454,8 @@ context(
.within(() => { .within(() => {
cy.getByTestId(viewProposalBtn).click(); cy.getByTestId(viewProposalBtn).click();
}); });
cy.getByTestId(proposalJsonToggle).click(); cy.getByTestId('proposal-terms-toggle').click();
cy.getByTestId(proposalJsonSection).within(() => { cy.getByTestId(proposalTermsSection).within(() => {
cy.contains('USDT Coin').should('be.visible'); cy.contains('USDT Coin').should('be.visible');
cy.contains('USDT').should('be.visible'); cy.contains('USDT').should('be.visible');
}); });
@@ -493,8 +463,8 @@ context(
it('Unable to submit new asset proposal with missing/invalid fields', function () { it('Unable to submit new asset proposal with missing/invalid fields', function () {
goToMakeNewProposal(governanceProposalType.NEW_ASSET); goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.getByTestId(proposalDownloadBtn).should('be.visible').click(); cy.get(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3); cy.get(inputError).should('have.length', 3);
}); });
it('Able to submit update asset proposal using min deadline', function () { it('Able to submit update asset proposal using min deadline', function () {
@@ -503,9 +473,9 @@ context(
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails(); enterUpdateAssetProposalDetails();
cy.getByTestId(minVoteDeadline).click(); cy.get(minVoteDeadline).click();
cy.getByTestId(minEnactDeadline).click(); cy.get(minEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -517,16 +487,13 @@ context(
}); });
}); });
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.getByTestId(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.getByTestId(proposalType) cy.get(proposalType)
.contains('Update asset') .contains('Update asset')
.parentsUntil(proposalListItem) .parentsUntil(proposalListItem)
.last() .last()
.within(() => { .within(() => {
cy.getByTestId(proposalDetails).should( cy.get(proposalDetails).should('contain.text', assetId.slice(0, 6)); // 3001-VOTE-029
'contain.text',
assetId.slice(0, 6)
); // 3001-VOTE-029
cy.getByTestId(viewProposalBtn).click(); cy.getByTestId(viewProposalBtn).click();
}); });
}); });
@@ -534,11 +501,13 @@ context(
.invoke('text') .invoke('text')
.should('not.be.empty'); .should('not.be.empty');
// 3001-VOTE-030 3001-VOTE-031 // 3001-VOTE-030 3001-VOTE-031
cy.getByTestId(proposalJsonToggle).click(); cy.getByTestId('proposal-terms-toggle').click();
cy.getByTestId(proposalJsonSection).within(() => { cy.getByTestId('proposal-terms').within(() => {
cy.contains(assetId).should('be.visible'); getProposalInformationFromTable('assetId').should('have.text', assetId);
cy.contains('lifetimeLimit').should('be.visible'); getProposalInformationFromTable('lifetimeLimit').should(
cy.contains('10').should('be.visible'); 'have.text',
'10'
);
}); });
}); });
@@ -546,9 +515,9 @@ context(
it('Able to submit update asset proposal using max deadline', function () { it('Able to submit update asset proposal using max deadline', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails(); enterUpdateAssetProposalDetails();
cy.getByTestId(maxVoteDeadline).click(); cy.get(maxVoteDeadline).click();
cy.getByTestId(maxEnactDeadline).click(); cy.get(maxEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -563,36 +532,36 @@ context(
it('Unable to submit edit asset proposal with missing/invalid fields', function () { it('Unable to submit edit asset proposal with missing/invalid fields', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
cy.getByTestId(proposalDownloadBtn).should('be.visible').click(); cy.get(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3); cy.get(inputError).should('have.length', 3);
}); });
it('Able to download and submit freeform proposal', function () { it('Able to download and submit freeform proposal', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM); goToMakeNewProposal(governanceProposalType.FREEFORM);
// 3008-PFRO-006 // 3008-PFRO-006
cy.getByTestId(newProposalTitle) cy.get(newProposalTitle)
.siblings() .siblings()
.should('contain.text', '(100 characters or less)'); // 3008-PFRO-007 .should('contain.text', '(100 characters or less)'); // 3008-PFRO-007
// 3008-PFRO-005 // 3008-PFRO-005
cy.getByTestId(newProposalTitle).type('Test freeform proposal form'); cy.get(newProposalTitle).type('Test freeform proposal form');
// 3008-PFRO-009 // 3008-PFRO-009
cy.getByTestId(newProposalDescription) cy.get(newProposalDescription)
.siblings() .siblings()
.should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010 .should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010
// 3008-PFRO-008 3002-PROP-012 3002-PROP-016 // 3008-PFRO-008 3002-PROP-012 3002-PROP-016
cy.getByTestId(newProposalDescription).type( cy.get(newProposalDescription).type(
'E2E test for downloading freeform proposal' 'E2E test for downloading freeform proposal'
); );
// 3008-PFRO-012 // 3008-PFRO-012
cy.getByTestId(minVoteDeadline).should('exist'); // 3002-PROP-008 cy.get(minVoteDeadline).should('exist'); // 3002-PROP-008
cy.getByTestId(maxVoteDeadline).should('exist'); cy.get(maxVoteDeadline).should('exist');
// 3008-PFRO-011 // 3008-PFRO-011
cy.getByTestId(proposalVoteDeadline).clear().type('2'); cy.get(proposalVoteDeadline).clear().type('2');
// 3008-PFRO-013 3008-PFRO-014 // 3008-PFRO-013 3008-PFRO-014
cy.getByTestId('voting-date').invoke('text').should('not.be.empty'); cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
// 3008-PFRO-015 // 3008-PFRO-015
cy.log('Download updated proposal file'); cy.log('Download updated proposal file');
cy.getByTestId(proposalDownloadBtn) cy.get(proposalDownloadBtn)
.should('be.visible') .should('be.visible')
.click() .click()
.then(() => { .then(() => {
@@ -626,23 +595,15 @@ context(
} }
function enterUpdateAssetProposalDetails() { function enterUpdateAssetProposalDetails() {
cy.getByTestId(newProposalTitle).type('Test update asset proposal'); cy.get(newProposalTitle).type('Test update asset proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals'); cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/update-asset').then((newAssetProposal) => { cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
const newAssetPayload = JSON.stringify(newAssetProposal); const newAssetPayload = JSON.stringify(newAssetProposal);
cy.getByTestId(newProposalTerms).type(newAssetPayload, { cy.get(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false, parseSpecialCharSequences: false,
delay: 2, delay: 2,
}); });
}); });
} }
function getMarketProposalDetailsFromTable(heading: string) {
return cy
.getByTestId('key-value-table-row')
.contains(heading)
.parent()
.siblings();
}
} }
); );
@@ -24,12 +24,12 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions'; import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
const proposalListItem = 'proposals-list-item'; const proposalListItem = 'proposals-list-item';
const openProposals = 'open-proposals'; const openProposals = '[data-testid="open-proposals"]';
const voteStatus = 'vote-status'; const voteStatus = 'vote-status';
const proposalType = 'proposal-type'; const proposalType = 'proposal-type';
const proposalStatus = 'proposal-status'; const proposalStatus = 'proposal-status';
const proposalClosingDate = 'vote-details'; const proposalClosingDate = '[data-testid="vote-details"]';
const viewProposalButton = 'view-proposal-btn'; const viewProposalButton = '[data-testid="view-proposal-btn"]';
const voteBreakDownToggle = 'vote-breakdown-toggle'; const voteBreakDownToggle = 'vote-breakdown-toggle';
describe('Governance flow for proposal list', { tags: '@slow' }, function () { describe('Governance flow for proposal list', { tags: '@slow' }, function () {
@@ -62,13 +62,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
} }
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.getByTestId(openProposals).within(() => { cy.get(openProposals).within(() => {
cy.getByTestId(proposalClosingDate) cy.get(proposalClosingDate)
.first() .first()
.invoke('text') .invoke('text')
.should('match', /days|minutes/); .should('match', /days|minutes/);
cy.getByTestId(proposalClosingDate).should('contain.text', 'months'); cy.get(proposalClosingDate).should('contain.text', 'months');
cy.getByTestId(proposalClosingDate).last().should('contain.text', 'year'); cy.get(proposalClosingDate).last().should('contain.text', 'year');
}); });
}); });
@@ -77,7 +77,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
const proposalTitle = generateFreeFormProposalTitle(); const proposalTitle = generateFreeFormProposalTitle();
submitUniqueRawProposal({ proposalTitle: proposalTitle }); submitUniqueRawProposal({ proposalTitle: proposalTitle });
cy.get('[data-testid="proposal-filter-toggle"]').click(); cy.get('[data-testid="set-proposals-filter-visible"]').click();
cy.get('[data-testid="filter-input"]').type(proposerId); cy.get('[data-testid="filter-input"]').type(proposerId);
// cy.get(`#${proposalId}`).should('contain', proposalId); // cy.get(`#${proposalId}`).should('contain', proposalId);
cy.contains(proposalTitle).should('be.visible'); cy.contains(proposalTitle).should('be.visible');
@@ -106,7 +106,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
createRawProposal(this.minProposerBalance); createRawProposal(this.minProposerBalance);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => { cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => { getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.getByTestId(viewProposalButton).should('be.visible'); cy.get(viewProposalButton).should('be.visible');
cy.getByTestId(proposalType).should('have.text', 'Freeform'); cy.getByTestId(proposalType).should('have.text', 'Freeform');
cy.getByTestId(proposalStatus).should('have.text', 'Open'); cy.getByTestId(proposalStatus).should('have.text', 'Open');
}); });
@@ -124,13 +124,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
'have.text', 'have.text',
'Participation not reached' 'Participation not reached'
); );
cy.getByTestId(viewProposalButton).click(); cy.get(viewProposalButton).click();
}); });
voteForProposal('for'); voteForProposal('for');
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => { getProposalFromTitle(proposalTitle).within(() => {
cy.getByTestId(voteStatus).should('have.text', 'Set to pass'); cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
cy.getByTestId(viewProposalButton).click(); cy.get(viewProposalButton).click();
}); });
cy.getByTestId(voteBreakDownToggle).click(); cy.getByTestId(voteBreakDownToggle).click();
getProposalInformationFromTable('Token participation met') getProposalInformationFromTable('Token participation met')
@@ -17,7 +17,8 @@ import {
} from '../../support/wallet-functions'; } from '../../support/wallet-functions';
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de'; const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked'; const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const rewardsTable = 'epoch-total-rewards-table'; const rewardsTable = 'epoch-total-rewards-table';
const txTimeout = Cypress.env('txTimeout'); const txTimeout = Cypress.env('txTimeout');
const rewardsTimeOut = { timeout: 60000 }; const rewardsTimeOut = { timeout: 60000 };
@@ -39,7 +40,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
cy.associateTokensToVegaWallet('6000'); cy.associateTokensToVegaWallet('6000');
navigateTo(navigation.validators); navigateTo(navigation.validators);
cy.VegaWalletTopUpRewardsPool(); cy.VegaWalletTopUpRewardsPool();
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should( cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain', 'contain',
'6,000.0', '6,000.0',
txTimeout txTimeout
@@ -4,6 +4,7 @@ import {
verifyStakedBalance, verifyStakedBalance,
verifyEthWalletTotalAssociatedBalance, verifyEthWalletTotalAssociatedBalance,
verifyEthWalletAssociatedBalance, verifyEthWalletAssociatedBalance,
waitForSpinner,
navigateTo, navigateTo,
navigation, navigation,
turnTelemetryOff, turnTelemetryOff,
@@ -57,7 +58,8 @@ context(
before('visit staking tab and connect vega wallet', function () { before('visit staking tab and connect vega wallet', function () {
cy.visit('/'); cy.visit('/');
ethereumWalletConnect(); ethereumWalletConnect();
cy.connectVegaWallet(); // this is a workaround for #2422 which can be removed once issue is resolved
cy.associateTokensToVegaWallet('4');
vegaWalletSetSpecifiedApprovalAmount('1000'); vegaWalletSetSpecifiedApprovalAmount('1000');
}); });
@@ -67,9 +69,10 @@ context(
function () { function () {
cy.clearLocalStorage(); cy.clearLocalStorage();
turnTelemetryOff(); turnTelemetryOff();
// Go to homepage to allow wallet teardown without epoch timer refreshing page cy.reload();
navigateTo(navigation.home); waitForSpinner();
vegaWalletTeardown(); cy.connectVegaWallet();
ethereumWalletConnect();
navigateTo(navigation.validators); navigateTo(navigation.validators);
} }
); );
@@ -127,7 +130,6 @@ context(
cy.getByTestId('staked-by-user-tooltip') cy.getByTestId('staked-by-user-tooltip')
.first() .first()
.should('have.text', 'Staked by me: 2.00'); .should('have.text', 'Staked by me: 2.00');
waitForBeginningOfEpoch();
cy.getByTestId('total-pending-stake').first().realHover(); cy.getByTestId('total-pending-stake').first().realHover();
cy.getByTestId('pending-user-stake-tooltip') cy.getByTestId('pending-user-stake-tooltip')
.first() .first()
@@ -398,7 +400,6 @@ context(
vegaWalletSetSpecifiedApprovalAmount('1000'); vegaWalletSetSpecifiedApprovalAmount('1000');
cy.reload(); cy.reload();
ethereumWalletConnect(); ethereumWalletConnect();
cy.connectVegaWallet();
stakingPageAssociateTokens('3'); stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0); verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
@@ -504,6 +505,11 @@ context(
); );
}); });
afterEach('Teardown Wallet', function () {
navigateTo(navigation.home);
vegaWalletTeardown();
});
function verifyNextEpochValue(amount: number) { function verifyNextEpochValue(amount: number) {
cy.getByTestId('stake-next-epoch', epochTimeout) cy.getByTestId('stake-next-epoch', epochTimeout)
.contains(amount, epochTimeout) .contains(amount, epochTimeout)
@@ -21,24 +21,25 @@ import {
vegaWalletTeardown, vegaWalletTeardown,
} from '../../support/wallet-functions'; } from '../../support/wallet-functions';
const ethWalletContainer = 'ethereum-wallet'; const ethWalletContainer = '[data-testid="ethereum-wallet"]';
const vegaWalletAssociatedBalance = 'currency-value'; const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked'; const vegaWalletUnstakedBalance =
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible'; '[data-testid="vega-wallet-balance-unstaked"]';
const associateWalletRadioButton = 'associate-radio-wallet';
const tokenAmountInputBox = 'token-amount-input';
const tokenSubmitButton = 'token-input-submit-button';
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
const vestingContractSection = 'vega-in-vesting-contract';
const vegaInWalletSection = 'vega-in-wallet';
const connectedVegaKey = 'connected-vega-key';
const associatedKey = 'associated-key';
const associatedAmount = 'associated-amount';
const associateCompleteText = 'transaction-complete-body';
const disassociationWarning = 'disassociation-warning';
const vegaWallet = 'aside [data-testid="vega-wallet"]';
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const txTimeout = Cypress.env('txTimeout'); const txTimeout = Cypress.env('txTimeout');
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
const associatedKey = '[data-testid="associated-key"]';
const associatedAmount = '[data-testid="associated-amount"]';
const associateCompleteText = '[data-testid="transaction-complete-body"]';
const disassociationWarning = '[data-testid="disassociation-warning"]';
const vegaWallet = 'aside [data-testid="vega-wallet"]';
context( context(
'Token association flow - with eth and vega wallets connected', 'Token association flow - with eth and vega wallets connected',
@@ -88,15 +89,12 @@ context(
verifyEthWalletAssociatedBalance('2.0'); verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0'); verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain', 'contain',
2.0 2.0
); );
}); });
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should( cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
} }
); );
@@ -129,7 +127,7 @@ context(
verifyEthWalletAssociatedBalance('1,001.00'); verifyEthWalletAssociatedBalance('1,001.00');
verifyEthWalletTotalAssociatedBalance('7,001.00'); verifyEthWalletTotalAssociatedBalance('7,001.00');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should(
'contain', 'contain',
'1,001.00' '1,001.00'
); );
@@ -139,20 +137,14 @@ context(
it('Able to disassociate a partial amount of tokens currently associated', function () { it('Able to disassociate a partial amount of tokens currently associated', function () {
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
}); });
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible'); cy.getByTestId('epoch-countdown').should('be.visible');
stakingPageDisassociateTokens('1'); stakingPageDisassociateTokens('1');
verifyEthWalletAssociatedBalance('1.0'); verifyEthWalletAssociatedBalance('1.0');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
'contain',
1.0
);
}); });
}); });
@@ -162,24 +154,21 @@ context(
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.'; 'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
}); });
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible'); cy.getByTestId('epoch-countdown').should('be.visible');
cy.get(ethWalletDissociateButton).click(); cy.get(ethWalletDissociateButton).click();
cy.getByTestId(disassociationWarning).should('contain', warningText); cy.get(disassociationWarning).should('contain', warningText);
stakingPageDisassociateAllTokens(); stakingPageDisassociateAllTokens();
cy.getByTestId(ethWalletContainer) cy.get(ethWalletContainer)
.first() .first()
.within(() => { .within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist' 'not.exist'
); );
}); });
cy.getByTestId(ethWalletContainer) cy.get(ethWalletContainer)
.first() .first()
.within(() => { .within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should( cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
@@ -187,10 +176,7 @@ context(
); );
}); });
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
'contain',
0.0
);
}); });
}); });
@@ -212,15 +198,9 @@ context(
verifyEthWalletAssociatedBalance('2.0'); verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0'); verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
}); });
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should( cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
stakingPageDisassociateTokens('1', { stakingPageDisassociateTokens('1', {
type: 'contract', type: 'contract',
skipConfirmation: true, skipConfirmation: true,
@@ -241,54 +221,45 @@ context(
cy.get('button').contains('Select a validator to nominate').click(); cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible'); cy.getByTestId('epoch-countdown').should('be.visible');
stakingPageAssociateTokens('37', { type: 'contract' }); stakingPageAssociateTokens('37', { type: 'contract' });
cy.getByTestId(vestingContractSection) cy.get(vestingContractSection)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId(associatedKey).should( cy.get(associatedKey).should(
'contain', 'contain',
Cypress.env('vegaWalletPublicKeyShort') Cypress.env('vegaWalletPublicKeyShort')
); );
cy.getByTestId(associatedAmount, txTimeout).should('contain', 37); cy.get(associatedAmount, txTimeout).should('contain', 37);
}); });
cy.getByTestId(vegaInWalletSection) cy.get(vegaInWalletSection)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId(associatedKey).should( cy.get(associatedKey).should(
'contain', 'contain',
Cypress.env('vegaWalletPublicKeyShort') Cypress.env('vegaWalletPublicKeyShort')
); );
cy.getByTestId(associatedAmount, txTimeout).should('contain', 21); cy.get(associatedAmount, txTimeout).should('contain', 21);
}); });
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
'contain',
58
);
}); });
stakingPageDisassociateTokens('6', { type: 'contract' }); stakingPageDisassociateTokens('6', { type: 'contract' });
cy.getByTestId(vestingContractSection) cy.get(vestingContractSection)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId(associatedAmount, txTimeout).should('contain', 31); cy.get(associatedAmount, txTimeout).should('contain', 31);
}); });
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
'contain',
52
);
}); });
navigateTo(navigation.validators); navigateTo(navigation.validators);
stakingPageDisassociateTokens('9', { type: 'wallet' }); stakingPageDisassociateTokens('9', { type: 'wallet' });
cy.getByTestId(vegaInWalletSection) cy.get(vegaInWalletSection)
.first() .first()
.within(() => { .within(() => {
cy.getByTestId(associatedAmount, txTimeout).should('contain', 12); cy.get(associatedAmount, txTimeout).should('contain', 12);
}); });
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
'contain',
43
);
}); });
}); });
@@ -297,10 +268,10 @@ context(
// 1004-ASSO-010 // 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled // No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).click(); cy.get(ethWalletAssociateButton).click();
cy.getByTestId(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.getByTestId(tokenAmountInputBox, { timeout: 10000 }).type('6500000'); cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled'); cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
}); });
// 1004-ASSO-004 // 1004-ASSO-004
@@ -325,25 +296,22 @@ context(
it('Able to associate tokens to different public key of connected vega wallet', function () { it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).click(); cy.get(ethWalletAssociateButton).click();
cy.getByTestId(associateWalletRadioButton).click(); cy.get(associateWalletRadioButton).click();
cy.getByTestId(connectedVegaKey).should( cy.get(connectedVegaKey).should(
'have.text', 'have.text',
Cypress.env('vegaWalletPublicKey') Cypress.env('vegaWalletPublicKey')
); );
switchVegaWalletPubKey(); switchVegaWalletPubKey();
cy.getByTestId(connectedVegaKey).should( cy.get(connectedVegaKey).should(
'have.text', 'have.text',
Cypress.env('vegaWalletPublicKey2') Cypress.env('vegaWalletPublicKey2')
); );
stakingPageAssociateTokens('2'); stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => { cy.get(vegaWallet).within(() => {
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should( cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
'contain',
2.0
);
}); });
cy.getByTestId(associateCompleteText).should( cy.get(associateCompleteText).should(
'have.text', 'have.text',
`Vega key ${Cypress.env( `Vega key ${Cypress.env(
'vegaWalletPublicKey2Short' 'vegaWalletPublicKey2Short'
@@ -116,6 +116,7 @@ context(
cy.getByTestId(amountInput).click().type('120'); cy.getByTestId(amountInput).click().type('120');
cy.getByTestId(submitWithdrawalButton).click(); cy.getByTestId(submitWithdrawalButton).click();
}); });
// assert withdrawal request
cy.getByTestId(toast) cy.getByTestId(toast)
.first(txTimeout) .first(txTimeout)
.should('contain.text', 'Funds unlocked') .should('contain.text', 'Funds unlocked')
@@ -10,13 +10,9 @@ import {
} from '../../support/governance.functions'; } from '../../support/governance.functions';
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions'; import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
const proposalDocsLink = 'proposal-docs-link'; const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
const proposalDocumentationLink = 'proposal-documentation-link';
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
const governanceDocsUrl = 'https://vega.xyz/governance'; const governanceDocsUrl = 'https://vega.xyz/governance';
const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item'; const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
const closedProposals = 'closed-proposals';
const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades';
context( context(
'Governance Page - verify elements on page', 'Governance Page - verify elements on page',
@@ -45,7 +41,7 @@ context(
it('should be able to see a working link for - find out more about Vega governance', function () { it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001 // 3001-VOTE-001
cy.getByTestId(proposalDocumentationLink) cy.get(proposalDocumentationLink)
.should('be.visible') .should('be.visible')
.and('have.text', 'Find out more about Vega governance') .and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href') .and('have.attr', 'href')
@@ -68,7 +64,7 @@ context(
// 3007-PNE-021 // 3007-PNE-021
it('should have documentation links for network parameter proposal', function () { it('should have documentation links for network parameter proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER); goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/network-parameter-proposal'); .and('contain', '/tutorials/proposals/network-parameter-proposal');
@@ -77,7 +73,7 @@ context(
// 3003-PMAN-002 3003-PMAN-005 // 3003-PMAN-002 3003-PMAN-005
it('should have documentation links for new market proposal', function () { it('should have documentation links for new market proposal', function () {
goToMakeNewProposal(governanceProposalType.NEW_MARKET); goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/new-market-proposal'); .and('contain', '/tutorials/proposals/new-market-proposal');
@@ -86,7 +82,7 @@ context(
// 3004-PMAC-005 // 3004-PMAC-005
it('should have documentation links for update market proposal', function () { it('should have documentation links for update market proposal', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET); goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/update-market-proposal'); .and('contain', '/tutorials/proposals/update-market-proposal');
@@ -95,7 +91,7 @@ context(
// 3005-PASN-002 005-PASN-005 // 3005-PASN-002 005-PASN-005
it('should have documentation links for new asset proposal', function () { it('should have documentation links for new asset proposal', function () {
goToMakeNewProposal(governanceProposalType.NEW_ASSET); goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/new-asset-proposal'); .and('contain', '/tutorials/proposals/new-asset-proposal');
@@ -104,7 +100,7 @@ context(
// 3006-PASC-002 3006-PASC-005 // 3006-PASC-002 3006-PASC-005
it('should have documentation links for update asset proposal', function () { it('should have documentation links for update asset proposal', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET); goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/update-asset-proposal'); .and('contain', '/tutorials/proposals/update-asset-proposal');
@@ -113,7 +109,7 @@ context(
// 3008-PFRO-003 3008-PFRO-017 // 3008-PFRO-003 3008-PFRO-017
it('should have documentation links for freeform proposal', function () { it('should have documentation links for freeform proposal', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM); goToMakeNewProposal(governanceProposalType.FREEFORM);
cy.getByTestId(proposalDocsLink) cy.getByTestId('proposal-docs-link')
.find('a') .find('a')
.should('have.attr', 'href') .should('have.attr', 'href')
.and('contain', '/tutorials/proposals/freeform-proposal'); .and('contain', '/tutorials/proposals/freeform-proposal');
@@ -121,7 +117,7 @@ context(
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () { it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
goToMakeNewProposal(governanceProposalType.RAW); goToMakeNewProposal(governanceProposalType.RAW);
cy.getByTestId(connectToVegaWalletButton) cy.get(connectToVegaWalletButton)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Vega wallet'); .and('have.text', 'Connect Vega wallet');
}); });
@@ -130,7 +126,7 @@ context(
mockNetworkUpgradeProposal(); mockNetworkUpgradeProposal();
cy.visit('/'); cy.visit('/');
cy.getByTestId('home-proposal-list').within(() => { cy.getByTestId('home-proposal-list').within(() => {
cy.getByTestId(networkUpgradeProposalListItem).should('exist'); cy.getByTestId('protocol-upgrade-proposals-list-item').should('exist');
cy.getByTestId('protocol-upgrade-proposal-title').should( cy.getByTestId('protocol-upgrade-proposal-title').should(
'have.text', 'have.text',
'Vega release v1' 'Vega release v1'
@@ -144,7 +140,11 @@ context(
cy.getByTestId('open-proposals').within(() => { cy.getByTestId('open-proposals').within(() => {
cy.get('li') cy.get('li')
.eq(0) .eq(0)
.should('have.attr', 'data-testid', networkUpgradeProposalListItem) .should(
'have.attr',
'data-testid',
'protocol-upgrade-proposals-list-item'
)
.within(() => { .within(() => {
cy.get('h2').should('have.text', 'Vega release v1'); cy.get('h2').should('have.text', 'Vega release v1');
cy.getByTestId('protocol-upgrade-proposal-type').should( cy.getByTestId('protocol-upgrade-proposal-type').should(
@@ -165,19 +165,18 @@ context(
); );
}); });
}); });
cy.getByTestId(closedProposals).within(() => { cy.getByTestId('closed-proposals').within(() => {
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist'); cy.getByTestId('protocol-upgrade-proposals-list-item').should(
}); 'have.length',
cy.getByTestId(closedProposalToggle).click(); 1
cy.getByTestId(closedProposals).within(() => { );
cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1);
}); });
}); });
it('should see details of network upgrade proposal', function () { it('should see details of network upgrade proposal', function () {
mockNetworkUpgradeProposal(); mockNetworkUpgradeProposal();
navigateTo(navigation.proposals); navigateTo(navigation.proposals);
cy.getByTestId(networkUpgradeProposalListItem) cy.getByTestId('protocol-upgrade-proposals-list-item')
.first() .first()
.find('[data-testid="view-proposal-btn"]') .find('[data-testid="view-proposal-btn"]')
.click(); .click();
@@ -214,18 +213,5 @@ context(
); );
}); });
}); });
it('filtering proposal should not display any network upgrade proposals', function () {
const proposalId =
'd848fc7881f13d366df5f61ab139d5fcfa72bf838151bb51b54381870e357931';
mockNetworkUpgradeProposal();
navigateTo(navigation.proposals);
cy.get('[data-testid="proposal-filter-toggle"]').click();
cy.get('[data-testid="filter-input"]').type(proposalId);
cy.getByTestId(closedProposals).should('have.length', 1);
cy.getByTestId(networkUpgradeProposalListItem).should('not.exist');
cy.getByTestId(closedProposalToggle).should('not.exist');
});
} }
); );
@@ -5,8 +5,8 @@ import {
} from '../../support/common.functions'; } from '../../support/common.functions';
import { waitForBeginningOfEpoch } from '../../support/staking.functions'; import { waitForBeginningOfEpoch } from '../../support/staking.functions';
const viewToggle = 'epoch-reward-view-toggle-total'; const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
const warning = 'callout'; const warning = '[data-testid="callout"]';
context( context(
'Rewards Page - verify elements on page', 'Rewards Page - verify elements on page',
@@ -27,7 +27,7 @@ context(
}); });
it('should have epoch warning', function () { it('should have epoch warning', function () {
cy.getByTestId(warning) cy.get(warning)
.should('be.visible') .should('be.visible')
.and( .and(
'have.text', 'have.text',
@@ -36,7 +36,7 @@ context(
}); });
it('should have toggle for seeing total vs individual rewards', function () { it('should have toggle for seeing total vs individual rewards', function () {
cy.getByTestId(viewToggle).should('be.visible'); cy.get(viewToggle).should('be.visible');
}); });
// Skipping due to bug #3471 causing flaky failuress // Skipping due to bug #3471 causing flaky failuress
@@ -1,17 +1,18 @@
import { navigateTo, navigation } from '../../support/common.functions'; import { navigateTo, navigation } from '../../support/common.functions';
const tokenDetailsTable = '.token-details'; const tokenDetailsTable = '.token-details';
const address = 'token-address'; const address = '[data-testid="token-address"]';
const contract = 'token-contract'; const contract = '[data-testid="token-contract"]';
const totalSupply = 'total-supply'; const totalSupply = '[data-testid="total-supply"]';
const circulatingSupply = 'circulating-supply'; const circulatingSupply = '[data-testid="circulating-supply"]';
const staked = 'staked'; const staked = '[data-testid="staked"]';
const tranchesLink = 'tranches-link'; const tranchesLink = '[data-testid="tranches-link"]';
const redeemBtn = 'check-vesting-page-btn'; const redeemBtn = '[data-testid="check-vesting-page-btn"]';
const getVegaWalletLink = 'get-vega-wallet-link'; const getVegaWalletLink = '[data-testid="get-vega-wallet-link"]';
const associateVegaLink = 'associate-vega-tokens-link-on-homepage'; const associateVegaLink =
const stakingBtn = 'staking-button-on-homepage'; '[data-testid="associate-vega-tokens-link-on-homepage"]';
const governanceBtn = 'governance-button-on-homepage'; const stakingBtn = '[data-testid="staking-button-on-homepage"]';
const governanceBtn = '[data-testid="governance-button-on-homepage"]';
const vegaTokenAddress = Cypress.env('vegaTokenAddress'); const vegaTokenAddress = Cypress.env('vegaTokenAddress');
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress'); const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
@@ -24,7 +25,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
describe('THE $VEGA TOKEN table', function () { describe('THE $VEGA TOKEN table', function () {
it('should have TOKEN ADDRESS', function () { it('should have TOKEN ADDRESS', function () {
cy.get(tokenDetailsTable).within(() => { cy.get(tokenDetailsTable).within(() => {
cy.getByTestId(address) cy.get(address)
.should('be.visible') .should('be.visible')
.invoke('text') .invoke('text')
.should('be.equal', vegaTokenAddress); .should('be.equal', vegaTokenAddress);
@@ -33,7 +34,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
it('should have VESTING CONTRACT', function () { it('should have VESTING CONTRACT', function () {
// 1004-ASSO-001 // 1004-ASSO-001
cy.get(tokenDetailsTable).within(() => { cy.get(tokenDetailsTable).within(() => {
cy.getByTestId(contract) cy.get(contract)
.should('be.visible') .should('be.visible')
.invoke('text') .invoke('text')
.should('be.equal', vegaTokenContractAddress); .should('be.equal', vegaTokenContractAddress);
@@ -41,56 +42,56 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
}); });
it('should have TOTAL SUPPLY', function () { it('should have TOTAL SUPPLY', function () {
cy.get(tokenDetailsTable).within(() => { cy.get(tokenDetailsTable).within(() => {
cy.getByTestId(totalSupply).should('be.visible'); cy.get(totalSupply).should('be.visible');
}); });
}); });
it('should have CIRCULATING SUPPLY', function () { it('should have CIRCULATING SUPPLY', function () {
cy.get(tokenDetailsTable).within(() => { cy.get(tokenDetailsTable).within(() => {
cy.getByTestId(circulatingSupply).should('be.visible'); cy.get(circulatingSupply).should('be.visible');
}); });
}); });
it('should have STAKED $VEGA', function () { it('should have STAKED $VEGA', function () {
cy.get(tokenDetailsTable).within(() => { cy.get(tokenDetailsTable).within(() => {
cy.getByTestId(staked).should('be.visible'); cy.get(staked).should('be.visible');
}); });
}); });
}); });
describe('links and buttons', function () { describe('links and buttons', function () {
it('should have TRANCHES link', function () { it('should have TRANCHES link', function () {
cy.getByTestId(tranchesLink) cy.get(tranchesLink)
.should('be.visible') .should('be.visible')
.and('have.attr', 'href') .and('have.attr', 'href')
.and('equal', '/token/tranches'); .and('equal', '/token/tranches');
}); });
it('should have REDEEM button', function () { it('should have REDEEM button', function () {
cy.getByTestId(redeemBtn) cy.get(redeemBtn)
.should('be.visible') .should('be.visible')
.parent() .parent()
.should('have.attr', 'href') .should('have.attr', 'href')
.and('equal', '/token/redeem'); .and('equal', '/token/redeem');
}); });
it('should have GET VEGA WALLET link', function () { it('should have GET VEGA WALLET link', function () {
cy.getByTestId(getVegaWalletLink) cy.get(getVegaWalletLink)
.should('be.visible') .should('be.visible')
.and('have.attr', 'href') .and('have.attr', 'href')
.and('equal', 'https://vega.xyz/wallet'); .and('equal', 'https://vega.xyz/wallet');
}); });
it('should have ASSOCIATE VEGA TOKENS link', function () { it('should have ASSOCIATE VEGA TOKENS link', function () {
cy.getByTestId(associateVegaLink) cy.get(associateVegaLink)
.should('be.visible') .should('be.visible')
.and('have.attr', 'href') .and('have.attr', 'href')
.and('equal', '/token/associate'); .and('equal', '/token/associate');
}); });
it('should have STAKING button', function () { it('should have STAKING button', function () {
cy.getByTestId(stakingBtn) cy.get(stakingBtn)
.should('be.visible') .should('be.visible')
.parent() .parent()
.should('have.attr', 'href') .should('have.attr', 'href')
.and('equal', '/validators'); .and('equal', '/validators');
}); });
it('should have GOVERNANCE button', function () { it('should have GOVERNANCE button', function () {
cy.getByTestId(governanceBtn) cy.get(governanceBtn)
.should('be.visible') .should('be.visible')
.parent() .parent()
.should('have.attr', 'href') .should('have.attr', 'href')
@@ -1,6 +1,5 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { import {
navigation, navigation,
verifyPageHeader, verifyPageHeader,
@@ -10,28 +9,29 @@ import {
clickOnValidatorFromList, clickOnValidatorFromList,
waitForBeginningOfEpoch, waitForBeginningOfEpoch,
} from '../../support/staking.functions'; } from '../../support/staking.functions';
import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
const guideLink = 'staking-guide-link'; const guideLink = '[data-testid="staking-guide-link"]';
const validatorTitle = 'validator-node-title'; const validatorTitle = '[data-testid="validator-node-title"]';
const validatorId = 'validator-id'; const validatorId = '[data-testid="validator-id"]';
const validatorPubKey = 'validator-public-key'; const validatorPubKey = '[data-testid="validator-public-key"]';
const ethAddressLink = 'link'; const ethAddressLink = '[data-testid="link"]';
const validatorStatus = 'validator-status'; const validatorStatus = '[data-testid="validator-status"]';
const totalStake = 'total-stake'; const totalStake = '[data-testid="total-stake"]';
const pendingStake = 'pending-stake'; const pendingStake = '[data-testid="pending-stake"]';
const stakedByOperator = 'staked-by-operator'; const stakedByOperator = '[data-testid="staked-by-operator"]';
const stakedByDelegates = 'staked-by-delegates'; const stakedByDelegates = '[data-testid="staked-by-delegates"]';
const stakeShare = 'stake-percentage'; const stakeShare = '[data-testid="stake-percentage"]';
const stakedByOperatorToolTip = 'staked-operator-tooltip'; const stakedByOperatorToolTip = '[data-testid="staked-operator-tooltip"]';
const stakedByDelegatesToolTip = 'staked-delegates-tooltip'; const stakedByDelegatesToolTip = '[data-testid="staked-delegates-tooltip"]';
const totalStakedToolTip = 'total-staked-tooltip'; const totalStakedToolTip = '[data-testid="total-staked-tooltip"]';
const unnormalisedVotingPowerToolTip = 'unnormalised-voting-power-tooltip'; const unnormalisedVotingPowerToolTip =
const normalisedVotingPowerToolTip = 'normalised-voting-power-tooltip'; '[data-testid="unnormalised-voting-power-tooltip"]';
const performancePenaltyToolTip = 'performance-penalty-tooltip'; const normalisedVotingPowerToolTip =
const overstakedPenaltyToolTip = 'overstaked-penalty-tooltip'; '[data-testid="normalised-voting-power-tooltip"]';
const multisigPenaltyToolTip = 'multisig-error-tooltip'; const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
const epochCountDown = 'epoch-countdown'; const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]';
const epochCountDown = '[data-testid="epoch-countdown"]';
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/; const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
context('Validators Page - verify elements on page', function () { context('Validators Page - verify elements on page', function () {
@@ -50,7 +50,7 @@ context('Validators Page - verify elements on page', function () {
it('Should have Staking Guide link visible', function () { it('Should have Staking Guide link visible', function () {
// 1002-STKE-003 // 1002-STKE-003
cy.getByTestId(guideLink) cy.get(guideLink)
.should('be.visible') .should('be.visible')
.and('have.text', 'Read more about staking on Vega') .and('have.text', 'Read more about staking on Vega')
.and( .and(
@@ -93,13 +93,13 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.getByTestId('total-stake').first().realHover(); cy.getByTestId('total-stake').first().realHover();
cy.getByTestId(stakedByOperatorToolTip) cy.get(stakedByOperatorToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Staked by operator: 3,000.00'); .should('contain', 'Staked by operator: 3,000.00');
cy.getByTestId(stakedByDelegatesToolTip) cy.get(stakedByDelegatesToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Staked by delegates: 0.00'); .should('contain', 'Staked by delegates: 0.00');
cy.getByTestId(totalStakedToolTip) cy.get(totalStakedToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Total stake: 3,000.00'); .should('contain', 'Total stake: 3,000.00');
}); });
@@ -116,10 +116,10 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.getByTestId('normalised-voting-power').first().realHover(); cy.getByTestId('normalised-voting-power').first().realHover();
cy.getByTestId(unnormalisedVotingPowerToolTip) cy.get(unnormalisedVotingPowerToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Unnormalised voting power: 20.00%'); .should('contain', 'Unnormalised voting power: 20.00%');
cy.getByTestId(normalisedVotingPowerToolTip) cy.get(normalisedVotingPowerToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Normalised voting power: 50.00%'); .should('contain', 'Normalised voting power: 50.00%');
}); });
@@ -137,12 +137,15 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.getByTestId('total-penalty').realHover(); cy.getByTestId('total-penalty').realHover();
cy.getByTestId(performancePenaltyToolTip) cy.get(performancePenaltyToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Performance penalty: 0.00%'); .should('contain', 'Performance penalty: 0.00%');
cy.getByTestId(overstakedPenaltyToolTip) cy.get(overstakedPenaltyToolTip)
.invoke('text') .invoke('text')
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886 .should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
cy.get(totalPenaltyToolTip)
.invoke('text')
.should('contain', 'Total penalties: 60.00%');
}); });
it('Should be able to see validator pending stake', function () { it('Should be able to see validator pending stake', function () {
@@ -152,22 +155,6 @@ context('Validators Page - verify elements on page', function () {
cy.wrap($pendingStake).should('contain.text', '0.00'); cy.wrap($pendingStake).should('contain.text', '0.00');
}); });
}); });
it('Should be able to see multisig error', function () {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'PreviousEpoch', previousEpochData);
});
waitForBeginningOfEpoch();
cy.getByTestId('total-penalty').first().realHover();
cy.getByTestId(multisigPenaltyToolTip)
.invoke('text')
.should('contain', 'Multisig penalty: 100%');
cy.getByTestId('total-penalty').eq(1).realHover();
cy.getByTestId(multisigPenaltyToolTip)
.invoke('text')
.should('contain', 'Multisig penalty: 100%');
});
} }
); );
@@ -183,59 +170,53 @@ context('Validators Page - verify elements on page', function () {
// 1002-STKE-006 // 1002-STKE-006
it('Should be able to see validator name', function () { it('Should be able to see validator name', function () {
cy.getByTestId(validatorTitle).should('not.be.empty'); cy.get(validatorTitle).should('not.be.empty');
}); });
// 1002-STKE-007 // 1002-STKE-007
it('Should be able to see validator id', function () { it('Should be able to see validator id', function () {
cy.getByTestId(validatorId).should('not.be.empty'); cy.get(validatorId).should('not.be.empty');
}); });
// 1002-STKE-008 // 1002-STKE-008
it('Should be able to see validator public key', function () { it('Should be able to see validator public key', function () {
cy.getByTestId(validatorPubKey).should('not.be.empty'); cy.get(validatorPubKey).should('not.be.empty');
}); });
// 1002-STKE-010 // 1002-STKE-010
it('Should be able to see Ethereum address', function () { it('Should be able to see Ethereum address', function () {
cy.getByTestId(ethAddressLink) cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href');
.should('not.be.empty')
.and('have.attr', 'href');
}); });
// TODO validators missing url for more information about them 1002-STKE-09 // TODO validators missing url for more information about them 1002-STKE-09
it('Should be able to see validator status', function () { it('Should be able to see validator status', function () {
cy.getByTestId(validatorStatus).should('have.text', 'Consensus'); cy.get(validatorStatus).should('have.text', 'Consensus');
}); });
// 1002-STKE-012 // 1002-STKE-012
it('Should be able to see total stake', function () { it('Should be able to see total stake', function () {
cy.getByTestId(totalStake) cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
.invoke('text')
.should('match', stakeNumberRegex);
}); });
it('Should be able to see pending stake', function () { it('Should be able to see pending stake', function () {
cy.getByTestId(pendingStake) cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
.invoke('text')
.should('match', stakeNumberRegex);
}); });
it('Should be able to see staked by operator', function () { it('Should be able to see staked by operator', function () {
cy.getByTestId(stakedByOperator) cy.get(stakedByOperator)
.invoke('text') .invoke('text')
.should('match', stakeNumberRegex); .should('match', stakeNumberRegex);
}); });
it('Should be able to see staked by delegates', function () { it('Should be able to see staked by delegates', function () {
cy.getByTestId(stakedByDelegates) cy.get(stakedByDelegates)
.invoke('text') .invoke('text')
.should('match', stakeNumberRegex); .should('match', stakeNumberRegex);
}); });
// 1002-STKE-051 // 1002-STKE-051
it('Should be able to see stake share in percentage', function () { it('Should be able to see stake share in percentage', function () {
cy.getByTestId(stakeShare) cy.get(stakeShare)
.invoke('text') .invoke('text')
.then(($stakePercentage) => { .then(($stakePercentage) => {
// The pattern must start at a word boundary (\b). // The pattern must start at a word boundary (\b).
@@ -261,7 +242,7 @@ context('Validators Page - verify elements on page', function () {
const epochTitle = 'h3'; const epochTitle = 'h3';
const nextEpochInfo = 'p'; const nextEpochInfo = 'p';
cy.getByTestId(epochCountDown).within(() => { cy.get(epochCountDown).within(() => {
cy.get(epochTitle).should('not.be.empty'); cy.get(epochTitle).should('not.be.empty');
cy.get(nextEpochInfo).should('contain.text', 'Next epoch'); cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
}); });
@@ -6,7 +6,7 @@ import {
} from '../../support/common.functions'; } from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions'; import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
const connectButton = 'connect-to-eth-btn'; const connectButton = '[data-testid="connect-to-eth-btn"]';
const lockedTokensInVestingContract = '6,499,972.30'; const lockedTokensInVestingContract = '6,499,972.30';
context( context(
@@ -29,7 +29,7 @@ context(
// 1005-VEST-018 // 1005-VEST-018
it('should have connect Eth wallet button', function () { it('should have connect Eth wallet button', function () {
cy.getByTestId(connectButton) cy.get(connectButton)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Ethereum wallet'); .and('have.text', 'Connect Ethereum wallet');
}); });
@@ -5,11 +5,11 @@ const walletContainer = 'aside [data-testid="ethereum-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1'; const walletHeader = '[data-testid="wallet-header"] h1';
const connectToEthButton = const connectToEthButton =
'[data-testid="connect-to-eth-wallet-button"]:visible'; '[data-testid="connect-to-eth-wallet-button"]:visible';
const connectorList = 'web3-connector-list'; const connectorList = '[data-testid="web3-connector-list"]';
const associate = '[href="/token/associate"]'; const associate = '[href="/token/associate"]';
const disassociate = '[href="/token/disassociate"]'; const disassociate = '[href="/token/disassociate"]';
const disconnect = 'disconnect-from-eth-wallet-button'; const disconnect = '[data-testid="disconnect-from-eth-wallet-button"]';
const accountNo = 'ethereum-account-truncated'; const accountNo = '[data-testid="ethereum-account-truncated"]';
const currencyTitle = '[data-testid="currency-title"]:visible'; const currencyTitle = '[data-testid="currency-title"]:visible';
const currencyValue = '[data-testid="currency-value"]:visible'; const currencyValue = '[data-testid="currency-value"]:visible';
const vegaInVesting = '[data-testid="vega-in-vesting-contract"]:visible'; const vegaInVesting = '[data-testid="vega-in-vesting-contract"]:visible';
@@ -18,8 +18,8 @@ const progressBar = '[data-testid="progress-bar"]:visible';
const currencyLocked = '[data-testid="currency-locked"]:visible'; const currencyLocked = '[data-testid="currency-locked"]:visible';
const currencyUnlocked = '[data-testid="currency-unlocked"]:visible'; const currencyUnlocked = '[data-testid="currency-unlocked"]:visible';
const dialog = '[role="dialog"]:visible'; const dialog = '[role="dialog"]:visible';
const dialogHeader = 'dialog-title'; const dialogHeader = '[data-testid="dialog-title"]';
const dialogCloseBtn = 'dialog-close'; const dialogCloseBtn = '[data-testid="dialog-close"]';
context( context(
'Ethereum Wallet - verify elements on widget', 'Ethereum Wallet - verify elements on widget',
@@ -59,7 +59,7 @@ context(
it('should have Connect Ethereum header visible', function () { it('should have Connect Ethereum header visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogHeader) cy.get(dialogHeader)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect to your Ethereum wallet'); .and('have.text', 'Connect to your Ethereum wallet');
}); });
@@ -73,7 +73,7 @@ context(
'WalletConnect', 'WalletConnect',
'WalletConnect Legacy', 'WalletConnect Legacy',
]; ];
cy.getByTestId(connectorList).within(() => { cy.get(connectorList).within(() => {
cy.get('button').each(($btn, i) => { cy.get('button').each(($btn, i) => {
cy.wrap($btn).should('be.visible').and('have.text', connectList[i]); cy.wrap($btn).should('be.visible').and('have.text', connectList[i]);
}); });
@@ -83,7 +83,7 @@ context(
after('close popup', function () { after('close popup', function () {
cy.get(dialog) cy.get(dialog)
.within(() => { .within(() => {
cy.getByTestId(dialogCloseBtn).click(); cy.get(dialogCloseBtn).click();
}) })
.should('not.exist'); .should('not.exist');
}); });
@@ -106,7 +106,7 @@ context(
// 0004-EWAL-005 // 0004-EWAL-005
it('should have account number visible', function () { it('should have account number visible', function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(accountNo) cy.get(accountNo)
.should('be.visible') .should('be.visible')
.and('have.text', Cypress.env('ethWalletPublicKeyTruncated')); .and('have.text', Cypress.env('ethWalletPublicKeyTruncated'));
}); });
@@ -129,7 +129,7 @@ context(
// 0004-EWAL-007 // 0004-EWAL-007
it('should have Disconnect button visible', function () { it('should have Disconnect button visible', function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(disconnect) cy.get(disconnect)
.should('be.visible') .should('be.visible')
.and('have.text', 'Disconnect'); .and('have.text', 'Disconnect');
}); });
@@ -7,28 +7,28 @@ import {
const walletContainer = 'aside [data-testid="vega-wallet"]'; const walletContainer = 'aside [data-testid="vega-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1'; const walletHeader = '[data-testid="wallet-header"] h1';
const connectButton = 'connect-vega-wallet'; const connectButton = '[data-testid="connect-vega-wallet"]';
const getVegaLink = 'link'; const getVegaLink = '[data-testid="link"]';
const dialog = '[role="dialog"]:visible'; const dialog = '[role="dialog"]:visible';
const dialogHeader = 'dialog-title'; const dialogHeader = '[data-testid="dialog-title"]';
const walletDialogHeader = 'wallet-dialog-title'; const walletDialogHeader = '[data-testid="wallet-dialog-title"]';
const connectorsList = 'connectors-list'; const connectorsList = '[data-testid="connectors-list"]';
const dialogCloseBtn = 'dialog-close'; const dialogCloseBtn = '[data-testid="dialog-close"]';
const restConnectorForm = 'rest-connector-form'; const restConnectorForm = '[data-testid="rest-connector-form"]';
const restWallet = '#wallet'; const restWallet = '#wallet';
const restPassphrase = '#passphrase'; const restPassphrase = '#passphrase';
const restConnectBtn = '[type="submit"]'; const restConnectBtn = '[type="submit"]';
const accountNo = 'vega-account-truncated'; const accountNo = '[data-testid="vega-account-truncated"]';
const currencyTitle = 'currency-title'; const currencyTitle = '[data-testid="currency-title"]';
const currencyValue = 'currency-value'; const currencyValue = '[data-testid="currency-value"]';
const vegaUnstaked = '[data-testid="vega-wallet-balance-unstaked"] .text-right'; const vegaUnstaked = '[data-testid="vega-wallet-balance-unstaked"] .text-right';
const governanceBtn = '[href="/proposals"]'; const governanceBtn = '[href="/proposals"]';
const stakingBtn = '[href="/validators"]'; const stakingBtn = '[href="/validators"]';
const manageLink = 'manage-vega-wallet'; const manageLink = '[data-testid="manage-vega-wallet"]';
const dialogVegaKey = 'vega-public-key-full'; const dialogVegaKey = '[data-testid="vega-public-key-full"]';
const dialogDisconnectBtn = 'disconnect'; const dialogDisconnectBtn = '[data-testid="disconnect"]';
const copyPublicKeyBtn = 'copy-vega-public-key'; const copyPublicKeyBtn = '[data-testid="copy-vega-public-key"]';
const vegaWalletCurrencyTitle = 'currency-title'; const vegaWalletCurrencyTitle = '[data-testid="currency-title"]';
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey'); const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
const txTimeout = Cypress.env('txTimeout'); const txTimeout = Cypress.env('txTimeout');
@@ -47,10 +47,10 @@ context(
cy.get(walletHeader) cy.get(walletHeader)
.should('be.visible') .should('be.visible')
.and('have.text', 'Vega Wallet'); .and('have.text', 'Vega Wallet');
cy.getByTestId(connectButton) cy.get(connectButton)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Vega wallet to use associated $VEGA'); .and('have.text', 'Connect Vega wallet to use associated $VEGA');
cy.getByTestId(getVegaLink) cy.get(getVegaLink)
.should('be.visible') .should('be.visible')
.and('have.text', 'Get a Vega wallet') .and('have.text', 'Get a Vega wallet')
.and('have.attr', 'href', 'https://vega.xyz/wallet'); .and('have.attr', 'href', 'https://vega.xyz/wallet');
@@ -61,20 +61,20 @@ context(
describe('when connect button clicked', () => { describe('when connect button clicked', () => {
before('click connect vega wallet button', () => { before('click connect vega wallet button', () => {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(connectButton).click(); cy.get(connectButton).click();
}); });
}); });
it('should have Connect Vega header visible', () => { it('should have Connect Vega header visible', () => {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(walletDialogHeader) cy.get(walletDialogHeader)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect'); .and('have.text', 'Connect');
}); });
}); });
it('should have jsonRpc and hosted connection options visible on list', function () { it('should have jsonRpc and hosted connection options visible on list', function () {
cy.getByTestId(connectorsList).within(() => { cy.get(connectorsList).within(() => {
cy.getByTestId('connector-jsonRpc') cy.getByTestId('connector-jsonRpc')
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Vega wallet'); .and('have.text', 'Connect Vega wallet');
@@ -86,33 +86,33 @@ context(
it('should have close button visible', function () { it('should have close button visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogCloseBtn).should('be.visible'); cy.get(dialogCloseBtn).should('be.visible');
}); });
}); });
}); });
describe('when rest connector form opened', function () { describe('when rest connector form opened', function () {
before('click hosted wallet app button', function () { before('click hosted wallet app button', function () {
cy.getByTestId(connectorsList).within(() => { cy.get(connectorsList).within(() => {
cy.getByTestId('connector-hosted').click(); cy.getByTestId('connector-hosted').click();
}); });
}); });
// 0002-WCON-002 // 0002-WCON-002
it('should have wallet field visible', function () { it('should have wallet field visible', function () {
cy.getByTestId(restConnectorForm).within(() => { cy.get(restConnectorForm).within(() => {
cy.get(restWallet).should('be.visible'); cy.get(restWallet).should('be.visible');
}); });
}); });
it('should have password field visible', function () { it('should have password field visible', function () {
cy.getByTestId(restConnectorForm).within(() => { cy.get(restConnectorForm).within(() => {
cy.get(restPassphrase).should('be.visible'); cy.get(restPassphrase).should('be.visible');
}); });
}); });
it('should have connect button visible', function () { it('should have connect button visible', function () {
cy.getByTestId(restConnectorForm).within(() => { cy.get(restConnectorForm).within(() => {
cy.get(restConnectBtn) cy.get(restConnectBtn)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect'); .and('have.text', 'Connect');
@@ -121,12 +121,12 @@ context(
it('should have close button visible', function () { it('should have close button visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogCloseBtn).should('be.visible'); cy.get(dialogCloseBtn).should('be.visible');
}); });
}); });
after('close dialog', function () { after('close dialog', function () {
cy.getByTestId(dialogCloseBtn).click().should('not.exist'); cy.get(dialogCloseBtn).click().should('not.exist');
}); });
}); });
@@ -152,7 +152,7 @@ context(
{ tags: '@smoke' }, { tags: '@smoke' },
function () { function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(accountNo) cy.get(accountNo)
.should('be.visible') .should('be.visible')
.and('have.text', Cypress.env('vegaWalletPublicKeyShort')); .and('have.text', Cypress.env('vegaWalletPublicKeyShort'));
}); });
@@ -161,7 +161,7 @@ context(
it('should have Vega Associated currency title visible', function () { it('should have Vega Associated currency title visible', function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(currencyTitle) cy.get(currencyTitle)
.should('be.visible') .should('be.visible')
.and('contain.text', `VEGAAssociated`); .and('contain.text', `VEGAAssociated`);
}); });
@@ -172,7 +172,7 @@ context(
{ tags: '@smoke' }, { tags: '@smoke' },
function () { function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(currencyValue) cy.get(currencyValue)
.should('be.visible') .should('be.visible')
.and('contain.text', `0.00`); .and('contain.text', `0.00`);
}); });
@@ -204,23 +204,21 @@ context(
it('should have Manage link visible', function () { it('should have Manage link visible', function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(manageLink) cy.get(manageLink).should('be.visible').and('have.text', 'Manage');
.should('be.visible')
.and('have.text', 'Manage');
}); });
}); });
describe('when Manage dialog opened', function () { describe('when Manage dialog opened', function () {
before('click Manage link', function () { before('click Manage link', function () {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(manageLink).click(); cy.get(manageLink).click();
}); });
}); });
// 0002-WCON-025, 0002-WCON-026 // 0002-WCON-025, 0002-WCON-026
it('should have SELECT A VEGA KEY dialog title visible', function () { it('should have SELECT A VEGA KEY dialog title visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogHeader) cy.get(dialogHeader)
.should('be.visible') .should('be.visible')
.and('have.text', 'SELECT A VEGA KEY'); .and('have.text', 'SELECT A VEGA KEY');
}); });
@@ -240,7 +238,7 @@ context(
'contain.text', 'contain.text',
truncatedPubKey1 truncatedPubKey1
); );
cy.getByTestId(dialogVegaKey) cy.get(dialogVegaKey)
.should('be.visible') .should('be.visible')
.and('contain.text', truncatedPubKey1) .and('contain.text', truncatedPubKey1)
.and('contain.text', truncatedPubKey2); .and('contain.text', truncatedPubKey2);
@@ -250,7 +248,7 @@ context(
// 0002-WCON-029 // 0002-WCON-029
it('should have copy public key button visible', function () { it('should have copy public key button visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(copyPublicKeyBtn) cy.get(copyPublicKeyBtn)
.should('be.visible') .should('be.visible')
.and('contain.text', 'Copy'); .and('contain.text', 'Copy');
}); });
@@ -258,13 +256,13 @@ context(
it('should have close button visible', function () { it('should have close button visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogCloseBtn).should('be.visible'); cy.get(dialogCloseBtn).should('be.visible');
}); });
}); });
it('should have vega Disconnect all keys button visible', function () { it('should have vega Disconnect all keys button visible', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogDisconnectBtn) cy.get(dialogDisconnectBtn)
.should('be.visible') .should('be.visible')
.and('have.text', 'Disconnect all keys'); .and('have.text', 'Disconnect all keys');
}); });
@@ -273,10 +271,10 @@ context(
// 0002-WCON-022 // 0002-WCON-022
it('should be able to disconnect all keys', function () { it('should be able to disconnect all keys', function () {
cy.get(dialog).within(() => { cy.get(dialog).within(() => {
cy.getByTestId(dialogDisconnectBtn).click(); cy.get(dialogDisconnectBtn).click();
}); });
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(connectButton).should('be.visible'); // 0002-WCON-023 cy.get(connectButton).should('be.visible'); // 0002-WCON-023
}); });
}); });
}); });
@@ -289,28 +287,28 @@ context(
name: 'USDC (fake)', name: 'USDC (fake)',
symbol: 'fUSDC', symbol: 'fUSDC',
amount: '1000000', amount: '1000000',
expectedAmount: 10.0, expectedAmount: '10.00',
}, },
{ {
id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665', id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665',
name: 'DAI (fake)', name: 'DAI (fake)',
symbol: 'fDAI', symbol: 'fDAI',
amount: '200000', amount: '200000',
expectedAmount: 2.0, expectedAmount: '2.00',
}, },
{ {
id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0', id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0',
name: 'BTC (fake)', name: 'BTC (fake)',
symbol: 'fBTC', symbol: 'fBTC',
amount: '600000', amount: '600000',
expectedAmount: 6.0, expectedAmount: '6.00',
}, },
{ {
id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567', id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567',
name: 'EURO (fake)', name: 'EURO (fake)',
symbol: 'fEURO', symbol: 'fEURO',
amount: '800000', amount: '800000',
expectedAmount: 8.0, expectedAmount: '8.00',
}, },
]; ];
@@ -332,20 +330,20 @@ context(
for (const { name, symbol, expectedAmount } of assets) { for (const { name, symbol, expectedAmount } of assets) {
it(`should see ${name} within vega wallet`, () => { it(`should see ${name} within vega wallet`, () => {
cy.get(walletContainer).within(() => { cy.get(walletContainer).within(() => {
cy.getByTestId(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name, txTimeout) .contains(name, txTimeout)
.should('be.visible'); .should('be.visible');
cy.getByTestId(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name) .contains(name)
.parent() .parent()
.siblings() .siblings()
.should((elementAmount) => { .invoke('text')
const displayedAmount = parseFloat(elementAmount.text()); .should('have.length.at.least', 4)
expect(displayedAmount).be.gte(expectedAmount); .then(parseFloat)
}); .should('be.gte', parseFloat(expectedAmount));
cy.getByTestId(vegaWalletCurrencyTitle) cy.get(vegaWalletCurrencyTitle)
.contains(name) .contains(name)
.parent() .parent()
.contains(symbol); .contains(symbol);
@@ -5,6 +5,8 @@ import {
verifyTabHighlighted, verifyTabHighlighted,
} from '../../support/common.functions'; } from '../../support/common.functions';
const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]';
context( context(
'Withdraw Page - verify elements on page', 'Withdraw Page - verify elements on page',
{ tags: '@smoke' }, { tags: '@smoke' },
@@ -24,7 +26,7 @@ context(
}); });
it('should have connect Vega wallet button', function () { it('should have connect Vega wallet button', function () {
cy.getByTestId('connect-to-vega-wallet-btn') cy.get(connectToVegaBtn)
.should('be.visible') .should('be.visible')
.and('have.text', 'Connect Vega wallet'); .and('have.text', 'Connect Vega wallet');
}); });
@@ -37,7 +37,7 @@ export function navigateTo(page: navigation) {
}); });
} else { } else {
return cy.get(navigation.section, { timeout: 10000 }).within(() => { return cy.get(navigation.section, { timeout: 10000 }).within(() => {
cy.get(page).eq(0).click({ force: true }); cy.get(page).eq(0).click();
}); });
} }
} }
@@ -139,9 +139,6 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
$associatedAmount $associatedAmount
); );
}); });
// Wait needed to allow Eth transaction to complete - otherwise could result in nonce error
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
} }
}); });
}); });

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