Compare commits
82
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2c82487d | ||
|
|
55143331f1 | ||
|
|
cafb3b1c57 | ||
|
|
019b2d7d89 | ||
|
|
de0dc4af8e | ||
|
|
6765f4d03a | ||
|
|
7bea90e4d1 | ||
|
|
ac4762f9d7 | ||
|
|
1195309b61 | ||
|
|
8ce77e23ba | ||
|
|
5cae2ce400 | ||
|
|
b8c9f9772e | ||
|
|
c3e39b6e15 | ||
|
|
77a391448b | ||
|
|
484d7888cf | ||
|
|
187f1929fe | ||
|
|
0a4333645b | ||
|
|
310506e5af | ||
|
|
0b33ed4299 | ||
|
|
13f2e51798 | ||
|
|
fc047feeee | ||
|
|
005455c870 | ||
|
|
2c2bc391e8 | ||
|
|
445a085190 | ||
|
|
bb1b236cdf | ||
|
|
da66b7b20d | ||
|
|
ec12811f72 | ||
|
|
180de8cf25 | ||
|
|
df88e77cdf | ||
|
|
9441aee8cf | ||
|
|
2353812834 | ||
|
|
bba2b3c177 | ||
|
|
ae57bd92f4 | ||
|
|
115b642140 | ||
|
|
ce3da97a8a | ||
|
|
cabd99d3ef | ||
|
|
597e07608f | ||
|
|
e451dc54b3 | ||
|
|
9703c3b7a6 | ||
|
|
c22b6f3ce9 | ||
|
|
c740c11eaa | ||
|
|
d1fabb31a3 | ||
|
|
94f045a60b | ||
|
|
1af375bab8 | ||
|
|
5a48ba4a33 | ||
|
|
d1fd9184ce | ||
|
|
8f29824f9e | ||
|
|
fc3c73ad24 | ||
|
|
1027827576 | ||
|
|
0089920d4c | ||
|
|
35896a9cf5 | ||
|
|
5a90ebe12e | ||
|
|
6be117086a | ||
|
|
9c6dd9f254 | ||
|
|
a675576a52 | ||
|
|
98d248e02e | ||
|
|
c8d55c6293 | ||
|
|
3467feb3e5 | ||
|
|
bdf1663709 | ||
|
|
d775573543 | ||
|
|
c0fdc8d570 | ||
|
|
a9ebb36b9b | ||
|
|
f6c0082f2d | ||
|
|
931ad75cc9 | ||
|
|
f25a58a3c3 | ||
|
|
37340b4dc3 | ||
|
|
17ba3eb351 | ||
|
|
8f966a4ba6 | ||
|
|
cc7f403718 | ||
|
|
9184c2374c | ||
|
|
37247a504a | ||
|
|
2e7a6a6458 | ||
|
|
bf6c13f523 | ||
|
|
a6f3a08d2f | ||
|
|
f13e456a29 | ||
|
|
5cab040189 | ||
|
|
e47b868c53 | ||
|
|
b6286cd0f3 | ||
|
|
f66e976b66 | ||
|
|
866e7232db | ||
|
|
5a8ff90890 | ||
|
|
7b8f654906 |
@@ -9,6 +9,11 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
@@ -27,14 +32,16 @@ jobs:
|
||||
|
||||
- name: resolve ipfs hashes for release
|
||||
run: |
|
||||
echo "Tag name: ${{ github.event.release.tag_name }}"
|
||||
echo "Name: ${{ github.event.release.name }}"
|
||||
echo "Description: ${{ github.event.release.body }}"
|
||||
until docker pull vegaprotocol/trading:${{ github.event.release.tag_name }}; do
|
||||
echo "Tag: ${{ github.event.release.tag_name }}"
|
||||
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:${{ github.event.release.tag_name }} cat /ipfs-hash > ipfs-hash
|
||||
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
|
||||
tar -xzf kubo.tgz
|
||||
export PATH="$PATH:$PWD/kubo"
|
||||
|
||||
@@ -6,9 +6,9 @@ on:
|
||||
- release/*
|
||||
- develop
|
||||
- main
|
||||
tags:
|
||||
- v*
|
||||
pull_request:
|
||||
# uncomment pull_request and comment pull_request_target to test CI changes against feature branch not target branch (develop)
|
||||
# pull_request:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- ready_for_review
|
||||
@@ -22,6 +22,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache
|
||||
@@ -47,7 +49,7 @@ jobs:
|
||||
|
||||
lint-pr-title:
|
||||
needs: node-modules
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
name: Verify PR title
|
||||
uses: ./.github/workflows/lint-pr.yml
|
||||
secrets: inherit
|
||||
@@ -62,6 +64,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
@@ -109,52 +112,82 @@ jobs:
|
||||
echo "Branch slug: ${branch_slug}"
|
||||
echo ">>>> eof debug"
|
||||
|
||||
projects_e2e=""
|
||||
projects_array=()
|
||||
|
||||
preview_governance="not deployed"
|
||||
preview_trading="not deployed"
|
||||
preview_explorer="not deployed"
|
||||
preview_tools="not deployed"
|
||||
|
||||
# parse if affected is any of three main applications, if none - use all of them
|
||||
if echo "$affected" | grep -q governance; then
|
||||
echo "Governance is affected"
|
||||
projects_e2e+='"governance-e2e" '
|
||||
projects_array+=("governance")
|
||||
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" '
|
||||
projects_array+=("trading")
|
||||
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" '
|
||||
projects_array+=("explorer")
|
||||
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" '
|
||||
if [[ ${#projects_array[@]} -eq 0 ]]; then
|
||||
projects_array=("governance" "trading" "explorer")
|
||||
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 echo "$affected" | grep -q multisig-signer; then
|
||||
echo "Tools are affected"
|
||||
# tools are only applicable to check previews or deploy from develop to mainnet
|
||||
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
||||
|
||||
# applications parsed before this loop are applicable for running e2e-tests
|
||||
projects_e2e_array=()
|
||||
for project in "${projects_array[@]}"; do
|
||||
projects_e2e_array+=("${project}-e2e")
|
||||
done
|
||||
# all applications below this loop are not applicable for running e2e-test
|
||||
|
||||
# check if pull request event to deploy tools
|
||||
if [[ "${{ github.event_name }}" = "pull_request" ]]; then
|
||||
if echo "$affected" | grep -q multisig-signer; then
|
||||
echo "Tools are affected"
|
||||
echo "Deploying tools on preview"
|
||||
preview_tools=$(printf "https://%s.%s.vega.rocks" "tools" "$branch_slug")
|
||||
projects+=' "multisig-signer" '
|
||||
|
||||
projects_array+=("multisig-signer")
|
||||
fi
|
||||
if [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
# those apps deploy only from develop to mainnet
|
||||
elif [[ "${{ github.ref }}" =~ .*develop$ ]]; then
|
||||
if echo "$affected" | grep -q multisig-signer; then
|
||||
echo "Tools are affected"
|
||||
echo "Deploying tools on s3"
|
||||
projects+=' "multisig-signer" '
|
||||
|
||||
projects_array+=("multisig-signer")
|
||||
fi
|
||||
if echo "$affected" | grep -q static; then
|
||||
echo "static is affected"
|
||||
echo "Deploying static on s3"
|
||||
|
||||
projects_array+=("static")
|
||||
fi
|
||||
if echo "$affected" | grep -q ui-toolkit; then
|
||||
echo "ui-toolkit is affected"
|
||||
echo "Deploying ui-toolkit on s3"
|
||||
|
||||
projects_array+=("ui-toolkit")
|
||||
fi
|
||||
fi
|
||||
projects_e2e=${projects_e2e%?}
|
||||
projects_e2e=[${projects_e2e// /,}]
|
||||
projects=${projects%?}
|
||||
projects=[${projects// /,}]
|
||||
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||
echo PROJECTS=$projects >> $GITHUB_ENV
|
||||
|
||||
echo "Projects: ${projects_array[@]}"
|
||||
echo "Projects E2E: ${projects_e2e_array[@]}"
|
||||
projects_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_array[@]}")
|
||||
projects_e2e_json=$(jq -M --compact-output --null-input '$ARGS.positional' --args -- "${projects_e2e_array[@]}")
|
||||
|
||||
echo PROJECTS_E2E=$projects_e2e_json >> $GITHUB_ENV
|
||||
echo PROJECTS=$projects_json >> $GITHUB_ENV
|
||||
|
||||
echo PREVIEW_GOVERNANCE=$preview_governance >> $GITHUB_ENV
|
||||
echo PREVIEW_TRADING=$preview_trading >> $GITHUB_ENV
|
||||
echo PREVIEW_EXPLORER=$preview_explorer >> $GITHUB_ENV
|
||||
@@ -171,7 +204,7 @@ jobs:
|
||||
cypress:
|
||||
needs: lint-test-build
|
||||
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
|
||||
secrets: inherit
|
||||
with:
|
||||
@@ -181,7 +214,7 @@ jobs:
|
||||
publish-dist:
|
||||
needs: lint-test-build
|
||||
name: '(CD) publish dist'
|
||||
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
# if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
|
||||
uses: ./.github/workflows/publish-dist.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
@@ -192,7 +225,7 @@ jobs:
|
||||
needs:
|
||||
- publish-dist
|
||||
- lint-test-build
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
timeout-minutes: 60
|
||||
name: '(CD) comment preview links'
|
||||
steps:
|
||||
|
||||
@@ -33,6 +33,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: './frontend-monorepo'
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
# Restore node_modules from cache if possible
|
||||
- name: Restore node_modules from cache
|
||||
|
||||
@@ -11,6 +11,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
@@ -19,6 +19,8 @@ jobs:
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Set up QEMU
|
||||
id: quemu
|
||||
@@ -31,6 +33,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to the Container registry (ghcr)
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -39,7 +42,7 @@ jobs:
|
||||
|
||||
- name: Log in to the Container registry (docker hub)
|
||||
uses: docker/login-action@v2
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
with:
|
||||
# registry: registry.hub.docker.com
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
@@ -74,10 +77,16 @@ jobs:
|
||||
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"
|
||||
elif [[ "${{ matrix.app}}" = "trading" ]] && [[ "${{ startsWith(github.ref, 'refs/tags/v') && 'true' || 'false' }}" = "true" ]]; then
|
||||
envName="mainnet"
|
||||
fi
|
||||
|
||||
if [[ "${envName}" = "mainnet" ]]; then
|
||||
@@ -106,14 +115,15 @@ jobs:
|
||||
run: |
|
||||
flags=""
|
||||
if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
|
||||
if [[ "${{ env.ENV_NAME }}" != "ops-vega" ]]; then
|
||||
flags="--env=${{ env.ENV_NAME }}"
|
||||
fi
|
||||
flags="--env=${{ env.ENV_NAME }}"
|
||||
fi
|
||||
|
||||
if [ "${{ matrix.app }}" = "trading" ]; then
|
||||
yarn nx export trading $flags || (yarn install && yarn nx export trading $flags)
|
||||
DIST_LOCATION=dist/apps/trading/exported
|
||||
elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
|
||||
NODE_ENV=production yarn nx run ui-toolkit:build-storybook
|
||||
DIST_LOCATION=dist/storybook/ui-toolkit
|
||||
else
|
||||
yarn nx build ${{ matrix.app }} $flags || (yarn install && yarn nx build ${{ matrix.app }} $flags)
|
||||
DIST_LOCATION=dist/apps/${{ matrix.app }}
|
||||
@@ -135,7 +145,7 @@ jobs:
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||
|
||||
- name: Image digest
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
- name: Sanity check docker image
|
||||
@@ -148,7 +158,9 @@ jobs:
|
||||
|
||||
- name: Publish dist as docker image (ghcr)
|
||||
uses: docker/build-push-action@v3
|
||||
if: ${{ github.event_name == 'pull_request' || (matrix.app == 'trading' && github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') ) }}
|
||||
continue-on-error: true
|
||||
id: ghcr-push
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -161,7 +173,9 @@ jobs:
|
||||
|
||||
- name: Publish dist as docker image (docker hub)
|
||||
uses: docker/build-push-action@v3
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
continue-on-error: true
|
||||
id: dockerhub-push
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
@@ -170,13 +184,41 @@ jobs:
|
||||
APP=${{ matrix.app }}
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.ref_name }}
|
||||
vegaprotocol/${{ matrix.app }}:mainnet
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||
|
||||
- name: Publish dist as docker image (ghcr - retry)
|
||||
uses: docker/build-push-action@v3
|
||||
if: ${{ steps.ghcr-push.outcome == 'failure' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
push: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Publish dist as docker image (docker hub - retry)
|
||||
uses: docker/build-push-action@v3
|
||||
if: ${{ steps.dockerhub-push.outcome == 'failure' }}
|
||||
with:
|
||||
context: .
|
||||
file: docker/node-outside-docker.Dockerfile
|
||||
push: true
|
||||
build-args: |
|
||||
APP=${{ matrix.app }}
|
||||
ENV_NAME=${{ env.ENV_NAME }}
|
||||
tags: |
|
||||
vegaprotocol/${{ matrix.app }}:${{ github.sha }}
|
||||
vegaprotocol/${{ matrix.app }}:${{ endsWith(github.ref, 'main') && 'mainnet' || endsWith(github.ref, 'release/testnet') && 'testnet' || '' }}
|
||||
|
||||
# bucket creation in github.com/vegaprotocol/terraform//frontend
|
||||
- name: Publish dist to s3
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') && ( matrix.app != 'trading' || (matrix.app == 'trading' && !endsWith(github.ref, 'main') ) ) }}
|
||||
# s3 releases are not happening for trading on mainnet - it's IPFS
|
||||
if: ${{ github.event_name == 'push' && ( matrix.app != 'trading' || (matrix.app == 'trading' && !( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) ) ) }}
|
||||
with:
|
||||
args: --acl private --follow-symlinks --delete
|
||||
env:
|
||||
@@ -188,28 +230,44 @@ jobs:
|
||||
|
||||
- name: Add preview label
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
|
||||
with:
|
||||
labels: ${{ matrix.app }}-preview
|
||||
number: ${{ github.event.number }}
|
||||
|
||||
- name: Trigger fleek deployment
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
# release to ipfs happens only on mainnet (represented by main branch) for trading
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'release/testnet') ) }}
|
||||
run: |
|
||||
# display info about app
|
||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
if echo ${{ github.ref }} | grep -q main; then
|
||||
# display info about app
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
|
||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
||||
curl -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
|
||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||
# display info about app
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "query{getSiteById(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id latestDeploy{id status}}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
|
||||
# trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
|
||||
curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query": "mutation{triggerDeploy(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id status}}"}' \
|
||||
https://api.fleek.co/graphql
|
||||
fi
|
||||
|
||||
- name: Check out ipfs-redirect
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: 'vegaprotocol/ipfs-redirect'
|
||||
@@ -217,11 +275,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
|
||||
- name: Update console.vega.xyz DNS to redirect to the new console
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
- name: Update interstitial page to point to the new console
|
||||
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( endsWith(github.ref, 'main') || endsWith(github.ref, 'testnet') ) }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
|
||||
run: |
|
||||
# set CID
|
||||
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
|
||||
export PATH="$PATH:$PWD/kubo"
|
||||
@@ -229,52 +288,28 @@ jobs:
|
||||
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
|
||||
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
|
||||
|
||||
ls -al ipfs-redirect
|
||||
|
||||
echo $new_hash > ipfs-redirect/cidv0.txt
|
||||
echo $new_cid > ipfs-redirect/cidv1.txt
|
||||
|
||||
(
|
||||
cd ipfs-redirect
|
||||
|
||||
# configure git
|
||||
git status
|
||||
cat .git/config
|
||||
git config --global user.email "vega-ci-bot@vega.xyz"
|
||||
git config --global user.name "vega-ci-bot"
|
||||
|
||||
branch_name="update-hash-${{ github.ref }}"
|
||||
git checkout -b "$branch_name"
|
||||
# update CID files
|
||||
if echo ${{ github.ref }} | grep -q main; then
|
||||
echo $new_hash > cidv0-mainnet.txt
|
||||
echo $new_cid > cidv1-mainnet.txt
|
||||
git add cidv0-mainnet.txt cidv1-mainnet.txt
|
||||
elif echo ${{ github.ref }} | grep -q release/testnet; then
|
||||
echo $new_hash > cidv0-fairground.txt
|
||||
echo $new_cid > cidv1-fairground.txt
|
||||
git add cidv0-fairground.txt cidv1-fairground.txt
|
||||
fi
|
||||
|
||||
# create commit
|
||||
commit_msg="Automated hash update from ${{ github.ref }}"
|
||||
git add cidv0.txt cidv1.txt
|
||||
git commit -m "$commit_msg"
|
||||
git push -u origin "$branch_name"
|
||||
pr_url="$(gh pr create --title "${commit_msg}" --body 'automated pull request to update CIDs')"
|
||||
echo $pr_url
|
||||
# once auto merge get's enabled on documentation repo let's do follow up
|
||||
sleep 5
|
||||
gh pr merge "${pr_url}" --delete-branch --squash --admin
|
||||
git push -u origin "main"
|
||||
)
|
||||
|
||||
# # Generate console URL
|
||||
# new_console_url_type=ipfs
|
||||
# # new_console_url_type=ipns
|
||||
# new_console_url_domain=cf-ipfs.com
|
||||
# # new_console_url_domain=dweb.link
|
||||
# new_console_url="https://${new_cid}.${new_console_url_type}.${new_console_url_domain}/"
|
||||
# echo "new_console_url=${new_console_url}"
|
||||
|
||||
# # Update record in DNSimple
|
||||
# # docs: https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord
|
||||
# dnsimple_account_id=84895
|
||||
# dnsimple_zone_name=console.vega.xyz
|
||||
# dnsimple_record_id=44409591
|
||||
# # see: https://dnsimple.com/a/84895/domains/console.vega.xyz/records/44409591/edit
|
||||
|
||||
# curl -H 'Authorization: Bearer ${{ secrets.DNSIMPLE_API_TOKEN }}' \
|
||||
# -H 'Accept: application/json' \
|
||||
# -H 'Content-Type: application/json' \
|
||||
# -X PATCH \
|
||||
# -d "{
|
||||
# \"content\": \"${new_console_url}\"
|
||||
# }" \
|
||||
# https://api.dnsimple.com/v2/${dnsimple_account_id}/zones/${dnsimple_zone_name}/records/${dnsimple_record_id}
|
||||
|
||||
@@ -5,7 +5,7 @@ NX_SENTRY_DSN=https://b3a56b03eda842faad731f3ea9dfd1bc@o286262.ingest.sentry.io/
|
||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/mainnet1/mainnet1.toml
|
||||
NX_VEGA_URL=https://api.vega.community/graphql
|
||||
NX_VEGA_ENV=MAINNET
|
||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest/
|
||||
NX_BLOCK_EXPLORER=https://be.vega.community/rest
|
||||
NX_ETHERSCAN_URL=https://etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz
|
||||
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.67.3/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"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
import WS from 'jest-websocket-mock';
|
||||
import useWebSocket from 'react-use-websocket';
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
fireEvent,
|
||||
act,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import { TendermintWebsocketContext } from '../../contexts/websocket/tendermint-websocket-context';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { BlocksRefetch } from './blocks-refetch';
|
||||
|
||||
const BlocksRefetchInWebsocketProvider = ({
|
||||
callback,
|
||||
mocketLocation,
|
||||
}: {
|
||||
callback: () => null;
|
||||
mocketLocation: string;
|
||||
}) => {
|
||||
const contextShape = useWebSocket(mocketLocation);
|
||||
|
||||
return (
|
||||
<TendermintWebsocketContext.Provider value={{ ...contextShape }}>
|
||||
<BlocksRefetch refetch={callback} />
|
||||
</TendermintWebsocketContext.Provider>
|
||||
);
|
||||
return <BlocksRefetch refetch={callback} />;
|
||||
};
|
||||
|
||||
describe('Blocks refetch', () => {
|
||||
@@ -32,111 +16,8 @@ describe('Blocks refetch', () => {
|
||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||
new WebSocket(mocketLocation);
|
||||
|
||||
render(
|
||||
<BlocksRefetchInWebsocketProvider
|
||||
callback={() => null}
|
||||
mocketLocation={mocketLocation}
|
||||
/>
|
||||
);
|
||||
await mocket.connected;
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('new blocks');
|
||||
render(<BlocksRefetchInWebsocketProvider callback={() => null} />);
|
||||
expect(screen.getByTestId('refresh')).toBeInTheDocument();
|
||||
mocket.close();
|
||||
});
|
||||
|
||||
it('should initiate callback when the button is clicked', async () => {
|
||||
const mocketLocation = 'wss:localhost:3003';
|
||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||
new WebSocket(mocketLocation);
|
||||
|
||||
const callback = jest.fn();
|
||||
render(
|
||||
<BlocksRefetchInWebsocketProvider
|
||||
callback={callback}
|
||||
mocketLocation={mocketLocation}
|
||||
/>
|
||||
);
|
||||
await mocket.connected;
|
||||
const button = screen.getByTestId('refresh');
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
expect(callback.mock.calls.length).toEqual(1);
|
||||
mocket.close();
|
||||
});
|
||||
|
||||
it('should show new blocks as websocket is correctly updated', async () => {
|
||||
const mocketLocation = 'wss:localhost:3004';
|
||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||
new WebSocket(mocketLocation);
|
||||
render(
|
||||
<BlocksRefetchInWebsocketProvider
|
||||
callback={() => null}
|
||||
mocketLocation={mocketLocation}
|
||||
/>
|
||||
);
|
||||
await mocket.connected;
|
||||
|
||||
// Ensuring we send an ID equal to the one the client subscribed with.
|
||||
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
||||
// @ts-ignore id on messages
|
||||
const id = mocket.messages[0].id;
|
||||
|
||||
const newBlockMessage = {
|
||||
id,
|
||||
result: {
|
||||
query: "tm.event = 'NewBlock'",
|
||||
},
|
||||
};
|
||||
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||
|
||||
act(() => {
|
||||
mocket.send(newBlockMessage);
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('1 new blocks');
|
||||
|
||||
act(() => {
|
||||
mocket.send(newBlockMessage);
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('2 new blocks');
|
||||
mocket.close();
|
||||
});
|
||||
|
||||
it('will not show new blocks if websocket has wrong ID', async () => {
|
||||
const mocketLocation = 'wss:localhost:3005';
|
||||
const mocket = new WS(mocketLocation, { jsonProtocol: true });
|
||||
new WebSocket(mocketLocation);
|
||||
|
||||
render(
|
||||
<BlocksRefetchInWebsocketProvider
|
||||
callback={() => null}
|
||||
mocketLocation={mocketLocation}
|
||||
/>
|
||||
);
|
||||
await mocket.connected;
|
||||
|
||||
// Ensuring we send an ID equal to the one the client subscribed with.
|
||||
await waitFor(() => expect(mocket.messages.length).toEqual(1));
|
||||
|
||||
const newBlockMessageBadId = {
|
||||
id: 'blahblahblah',
|
||||
result: {
|
||||
query: "tm.event = 'NewBlock'",
|
||||
},
|
||||
};
|
||||
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||
|
||||
act(() => {
|
||||
mocket.send(newBlockMessageBadId);
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('new-blocks')).toHaveTextContent('0 new blocks');
|
||||
mocket.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,36 +1,19 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTendermintWebsocket } from '../../hooks/use-tendermint-websocket';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface BlocksRefetchProps {
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
export const BlocksRefetch = ({ refetch }: BlocksRefetchProps) => {
|
||||
const [blocksToLoad, setBlocksToLoad] = useState<number>(0);
|
||||
|
||||
const { messages } = useTendermintWebsocket({
|
||||
query: "tm.event = 'NewBlock'",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (messages.length > 0) {
|
||||
setBlocksToLoad((prev) => prev + 1);
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
const refresh = () => {
|
||||
refetch();
|
||||
setBlocksToLoad(0);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<span data-testid="new-blocks">{blocksToLoad} new blocks - </span>
|
||||
<ButtonLink onClick={refresh} data-testid="refresh">
|
||||
{t('refresh to see latest')}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<Button onClick={refresh} data-testid="refresh" size="xs">
|
||||
<Icon name="refresh" className="!align-baseline mr-2" size={3} />
|
||||
{t('Load new')}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||
hide={window.innerWidth <= BREAKPOINT_MD}
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<MarketFieldsFragment, 'state'>) => {
|
||||
}: VegaValueGetterParams<MarketFieldsFragment>) => {
|
||||
return data?.state ? MarketStateMapping[data?.state] : '-';
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
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,6 +7,7 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export type LiquidityAmendment =
|
||||
components['schemas']['v1LiquidityProvisionAmendment'];
|
||||
@@ -34,6 +35,10 @@ export const TxDetailsLiquidityAmendment = ({
|
||||
txData.command.liquidityProvisionAmendment;
|
||||
const marketId: string = amendment.marketId || '-';
|
||||
|
||||
const fee = amendment.fee
|
||||
? new BigNumber(amendment.fee).times(100).toString()
|
||||
: '-';
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -63,7 +68,7 @@ export const TxDetailsLiquidityAmendment = ({
|
||||
{amendment.fee ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Fee')}</TableCell>
|
||||
<TableCell>{amendment.fee}%</TableCell>
|
||||
<TableCell>{fee}%</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
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,6 +7,7 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
|
||||
import PriceInMarket from '../../price-in-market/price-in-market';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export type LiquiditySubmission =
|
||||
components['schemas']['v1LiquidityProvisionSubmission'];
|
||||
@@ -33,6 +34,10 @@ export const TxDetailsLiquiditySubmission = ({
|
||||
txData.command.liquidityProvisionSubmission;
|
||||
const marketId: string = submission.marketId || '-';
|
||||
|
||||
const fee = submission.fee
|
||||
? new BigNumber(submission.fee).times(100).toString()
|
||||
: '-';
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -62,7 +67,7 @@ export const TxDetailsLiquiditySubmission = ({
|
||||
{submission.fee ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Fee')}</TableCell>
|
||||
<TableCell>{submission.fee}%</TableCell>
|
||||
<TableCell>{fee}%</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
export interface FilterLabelProps {
|
||||
filters: Set<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the list (currently limited to 1) of filters set by the
|
||||
* Transaction Filter
|
||||
*/
|
||||
export function FilterLabel({ filters }: FilterLabelProps) {
|
||||
if (!filters || filters.size !== 1) {
|
||||
return <span className="uppercase">{t('Filter')}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className="uppercase">{t('Filters')}:</span>
|
||||
<code className="bg-vega-light-150 px-2 rounded-md capitalize">
|
||||
{Array.from(filters)[0]}
|
||||
</code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItemIndicator,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuSubContent,
|
||||
Icon,
|
||||
Button,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { FilterLabel } from './tx-filter-label';
|
||||
|
||||
// All possible transaction types. Should be generated.
|
||||
export type FilterOption =
|
||||
| 'Amend LiquidityProvision Order'
|
||||
| 'Amend Order'
|
||||
| 'Batch Market Instructions'
|
||||
| 'Cancel LiquidityProvision Order'
|
||||
| 'Cancel Order'
|
||||
| 'Cancel Transfer Funds'
|
||||
| 'Chain Event'
|
||||
| 'Delegate'
|
||||
| 'Ethereum Key Rotate Submission'
|
||||
| 'Issue Signatures'
|
||||
| 'Key Rotate Submission'
|
||||
| 'Liquidity Provision Order'
|
||||
| 'Node Signature'
|
||||
| 'Node Vote'
|
||||
| 'Proposal'
|
||||
| 'Protocol Upgrade'
|
||||
| 'Register new Node'
|
||||
| 'State Variable Proposal'
|
||||
| 'Submit Oracle Data'
|
||||
| 'Submit Order'
|
||||
| 'Transfer Funds'
|
||||
| 'Undelegate'
|
||||
| 'Validator Heartbeat'
|
||||
| 'Vote on Proposal'
|
||||
| 'Withdraw';
|
||||
|
||||
// Alphabetised list of transaction types to appear at the top level
|
||||
export const PrimaryFilterOptions: FilterOption[] = [
|
||||
'Amend LiquidityProvision Order',
|
||||
'Amend Order',
|
||||
'Batch Market Instructions',
|
||||
'Cancel LiquidityProvision Order',
|
||||
'Cancel Order',
|
||||
'Cancel Transfer Funds',
|
||||
'Delegate',
|
||||
'Liquidity Provision Order',
|
||||
'Proposal',
|
||||
'Submit Oracle Data',
|
||||
'Submit Order',
|
||||
'Transfer Funds',
|
||||
'Undelegate',
|
||||
'Vote on Proposal',
|
||||
'Withdraw',
|
||||
];
|
||||
|
||||
// Alphabetised list of transaction types to nest under a 'More...' submenu
|
||||
export const SecondaryFilterOptions: FilterOption[] = [
|
||||
'Chain Event',
|
||||
'Ethereum Key Rotate Submission',
|
||||
'Issue Signatures',
|
||||
'Key Rotate Submission',
|
||||
'Node Signature',
|
||||
'Node Vote',
|
||||
'Protocol Upgrade',
|
||||
'Register new Node',
|
||||
'State Variable Proposal',
|
||||
'Validator Heartbeat',
|
||||
];
|
||||
|
||||
export const AllFilterOptions: FilterOption[] = [
|
||||
...PrimaryFilterOptions,
|
||||
...SecondaryFilterOptions,
|
||||
];
|
||||
|
||||
export interface TxFilterProps {
|
||||
filters: Set<FilterOption>;
|
||||
setFilters: Dispatch<SetStateAction<Set<FilterOption>>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a structured dropdown menu of all of the available transaction
|
||||
* 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
|
||||
* one or all.
|
||||
* @param filters null or Set of tranaction types
|
||||
* @param setFilters A function to update the filters prop
|
||||
* @returns
|
||||
*/
|
||||
export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
|
||||
return (
|
||||
<DropdownMenu
|
||||
modal={false}
|
||||
trigger={
|
||||
<DropdownMenuTrigger className="ml-2">
|
||||
<Button size="xs">
|
||||
<FilterLabel filters={filters} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{filters.size > 1 ? null : (
|
||||
<>
|
||||
<DropdownMenuCheckboxItem
|
||||
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
|
||||
>
|
||||
{t('Clear filters')} <Icon name="cross" />
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
)}
|
||||
{PrimaryFilterOptions.map((f) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={f}
|
||||
checked={filters.has(f)}
|
||||
onCheckedChange={() => {
|
||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||
setFilters(new Set([f]));
|
||||
}}
|
||||
id={`radio-${f}`}
|
||||
>
|
||||
{f}
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon name="tick-circle" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
{t('More Types')}
|
||||
<Icon name="chevron-right" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
{SecondaryFilterOptions.map((f) => (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={f}
|
||||
checked={filters.has(f)}
|
||||
onCheckedChange={(checked) => {
|
||||
// NOTE: These act like radio buttons until the API supports multiple filters
|
||||
setFilters(new Set([f]));
|
||||
}}
|
||||
id={`radio-${f}`}
|
||||
>
|
||||
{f}
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon name="tick-circle" className="inline" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
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';
|
||||
@@ -69,6 +69,17 @@ export const TxsInfiniteList = ({
|
||||
}: TxsInfiniteListProps) => {
|
||||
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) {
|
||||
@@ -110,6 +121,7 @@ export const TxsInfiniteList = ({
|
||||
isItemLoaded={isItemLoaded}
|
||||
itemCount={itemCount}
|
||||
loadMoreItems={loadMoreItems}
|
||||
ref={infiniteLoaderRef}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<List
|
||||
|
||||
@@ -33,7 +33,7 @@ export const getTxsDataUrl = ({ limit, filters }: IGetTxsDataUrl) => {
|
||||
// Hacky fix for param as array
|
||||
let urlAsString = url.toString();
|
||||
if (filters) {
|
||||
urlAsString += '&' + filters;
|
||||
urlAsString += '&' + filters.replace(' ', '%20');
|
||||
}
|
||||
|
||||
return urlAsString;
|
||||
@@ -65,6 +65,14 @@ export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
||||
}
|
||||
}, [setTxsState, data]);
|
||||
|
||||
useEffect(() => {
|
||||
setTxsState((prev) => ({
|
||||
txsData: [],
|
||||
hasMoreTxs: true,
|
||||
lastCursor: '',
|
||||
}));
|
||||
}, [filters]);
|
||||
|
||||
const loadTxs = useCallback(() => {
|
||||
return refetch({
|
||||
limit: limit,
|
||||
|
||||
@@ -5,17 +5,43 @@ import { TxsInfiniteList } from '../../../components/txs';
|
||||
import { useTxsData } from '../../../hooks/use-txs-data';
|
||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
|
||||
const BE_TXS_PER_REQUEST = 20;
|
||||
import { useState } from 'react';
|
||||
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
|
||||
|
||||
const BE_TXS_PER_REQUEST = 15;
|
||||
|
||||
export const TxsList = () => {
|
||||
useDocumentTitle(['Transactions']);
|
||||
|
||||
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
||||
useTxsData({ limit: BE_TXS_PER_REQUEST });
|
||||
return (
|
||||
<section className="md:p-2 lg:p-4 xl:p-6">
|
||||
<section className="md:p-2 lg:p-4 xl:p-6 relative">
|
||||
<RouteTitle>{t('Transactions')}</RouteTitle>
|
||||
<BlocksRefetch refetch={refreshTxs} />
|
||||
<TxsListFiltered />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export const TxsListFiltered = () => {
|
||||
const [filters, setFilters] = useState(new Set(AllFilterOptions));
|
||||
|
||||
const f =
|
||||
filters && filters.size === 1
|
||||
? `filters[cmd.type]=${Array.from(filters)[0]}`
|
||||
: '';
|
||||
|
||||
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
|
||||
useTxsData({
|
||||
limit: BE_TXS_PER_REQUEST,
|
||||
filters: f,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<menu className="mb-2">
|
||||
<BlocksRefetch refetch={refreshTxs} />
|
||||
<TxsFilter filters={filters} setFilters={setFilters} />
|
||||
</menu>
|
||||
|
||||
<TxsInfiniteList
|
||||
hasMoreTxs={hasMoreTxs}
|
||||
areTxsLoading={loading}
|
||||
@@ -24,6 +50,6 @@ export const TxsList = () => {
|
||||
error={error}
|
||||
className="mb-28"
|
||||
/>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+428
-421
File diff suppressed because it is too large
Load Diff
@@ -49,7 +49,7 @@ module.exports = defineConfig({
|
||||
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
|
||||
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
|
||||
txTimeout: { timeout: 70000 },
|
||||
epochTimeout: { timeout: 6000 },
|
||||
epochTimeout: { timeout: 12000 },
|
||||
blockConfirmations: 3,
|
||||
grepTags: '@regression @smoke @slow',
|
||||
grepFilterSpecs: true,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
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',
|
||||
},
|
||||
};
|
||||
@@ -14,25 +14,31 @@ import {
|
||||
submitUniqueRawProposal,
|
||||
voteForProposal,
|
||||
} from '../../../../governance-e2e/src/support/governance.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../../../governance-e2e/src/support/staking.functions';
|
||||
import {
|
||||
ensureSpecifiedUnstakedTokensAreAssociated,
|
||||
stakingPageAssociateTokens,
|
||||
stakingPageDisassociateAllTokens,
|
||||
} from '../../../../governance-e2e/src/support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../../../governance-e2e/src/support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../../../governance-e2e/src/support/wallet-teardown.functions';
|
||||
import {
|
||||
switchVegaWalletPubKey,
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
} from '../../support/wallet-functions';
|
||||
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
|
||||
|
||||
const proposalVoteProgressForPercentage =
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
'vote-progress-indicator-percentage-for';
|
||||
const proposalVoteProgressAgainstPercentage =
|
||||
'[data-testid="vote-progress-indicator-percentage-against"]';
|
||||
const proposalVoteProgressForTokens =
|
||||
'[data-testid="vote-progress-indicator-tokens-for"]';
|
||||
'vote-progress-indicator-percentage-against';
|
||||
const proposalVoteProgressForTokens = 'vote-progress-indicator-tokens-for';
|
||||
const proposalVoteProgressAgainstTokens =
|
||||
'[data-testid="vote-progress-indicator-tokens-against"]';
|
||||
const changeVoteButton = '[data-testid="change-vote-button"]';
|
||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
'vote-progress-indicator-tokens-against';
|
||||
const changeVoteButton = 'change-vote-button';
|
||||
const proposalDetailsTitle = 'proposal-title';
|
||||
const proposalDetailsDescription = 'proposal-description';
|
||||
const openProposals = 'open-proposals';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const proposalDescriptionToggle = 'proposal-description-toggle';
|
||||
const voteBreakdownToggle = 'vote-breakdown-toggle';
|
||||
const proposalTermsToggle = 'proposal-json-toggle';
|
||||
@@ -44,7 +50,7 @@ describe(
|
||||
before('connect wallets and set approval limit', function () {
|
||||
cy.visit('/');
|
||||
ethereumWalletConnect();
|
||||
cy.associateTokensToVegaWallet('1');
|
||||
// cy.associateTokensToVegaWallet('1');
|
||||
});
|
||||
|
||||
beforeEach('visit proposals tab', function () {
|
||||
@@ -65,18 +71,18 @@ describe(
|
||||
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.get(viewProposalButton).should('be.visible').click();
|
||||
cy.getByTestId(viewProposalButton).should('be.visible').click();
|
||||
});
|
||||
});
|
||||
cy.get(proposalDetailsTitle).should(
|
||||
cy.getByTestId(proposalDetailsTitle).should(
|
||||
'contain.text',
|
||||
rawProposal.rationale.title
|
||||
);
|
||||
cy.getByTestId(proposalDescriptionToggle).click();
|
||||
cy.getByTestId('proposal-description-toggle');
|
||||
cy.get(proposalDetailsDescription)
|
||||
cy.getByTestId(proposalDetailsDescription)
|
||||
.find('p')
|
||||
.should('have.text', proposalDescription);
|
||||
});
|
||||
@@ -110,7 +116,7 @@ describe(
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
cy.wrap(
|
||||
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
|
||||
@@ -132,7 +138,7 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
|
||||
@@ -159,7 +165,7 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-080
|
||||
@@ -176,14 +182,16 @@ describe(
|
||||
.contains(votedDate)
|
||||
.should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
cy.getByTestId(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
.contains('0.00%')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressForTokens).contains('1.00').and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
.contains('1.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
@@ -204,15 +212,15 @@ describe(
|
||||
getProposalInformationFromTable('Number of voting parties')
|
||||
.should('have.text', '1')
|
||||
.and('be.visible');
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-064
|
||||
getProposalInformationFromTable('Tokens for proposal')
|
||||
.should('have.text', (1).toFixed(2))
|
||||
.and('be.visible');
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('against');
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
getProposalInformationFromTable('Tokens against proposal')
|
||||
@@ -229,13 +237,15 @@ describe(
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
voteForProposal('for');
|
||||
// 3001-VOTE-079
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
.contains('1')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
getProposalInformationFromTable('Total Supply')
|
||||
.invoke('text')
|
||||
@@ -251,22 +261,22 @@ describe(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
cy.getByTestId(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
cy.getByTestId(proposalVoteProgressAgainstPercentage)
|
||||
.contains('0.00%')
|
||||
.and('be.visible');
|
||||
// 3001-VOTE-065
|
||||
cy.get(changeVoteButton).should('be.visible').click();
|
||||
cy.getByTestId(changeVoteButton).should('be.visible').click();
|
||||
voteForProposal('for');
|
||||
cy.get(proposalVoteProgressForTokens)
|
||||
cy.getByTestId(proposalVoteProgressForTokens)
|
||||
.contains(tokensRequiredToAchieveResult)
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
cy.getByTestId(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.getByTestId(voteBreakdownToggle).click();
|
||||
@@ -297,5 +307,36 @@ describe(
|
||||
.and('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to vote for proposal twice by switching public key', function () {
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||
createRawProposal();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
voteForProposal('for');
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
ethereumWalletConnect();
|
||||
switchVegaWalletPubKey();
|
||||
stakingPageAssociateTokens('2');
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
cy.getByTestId('you-voted').should('not.exist');
|
||||
voteForProposal('against');
|
||||
cy.contains('You voted: Against').should('be.visible');
|
||||
switchVegaWalletPubKey();
|
||||
cy.getByTestId(proposalVoteProgressForTokens).should(
|
||||
'contain.text',
|
||||
'1.00'
|
||||
);
|
||||
// Checking vote status for different public keys is displayed correctly
|
||||
cy.contains('You voted: For').should('be.visible');
|
||||
});
|
||||
switchVegaWalletPubKey();
|
||||
stakingPageDisassociateAllTokens();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -16,16 +16,16 @@ import {
|
||||
} from '../../support/proposal.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const closedProposals = '[data-testid="closed-proposals"]';
|
||||
const proposalStatus = '[data-testid="proposal-status"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const votesTable = '[data-testid="votes-table"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const closedProposals = 'closed-proposals';
|
||||
const proposalStatus = 'proposal-status';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const votesTable = 'votes-table';
|
||||
const openProposals = 'open-proposals';
|
||||
const proposalVoteProgressForPercentage =
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
'vote-progress-indicator-percentage-for';
|
||||
const proposalTimeout = { timeout: 8000 };
|
||||
|
||||
context(
|
||||
@@ -55,18 +55,18 @@ context(
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.get(closedProposals).within(() => {
|
||||
cy.getByTestId(closedProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(viewProposalButton).click();
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
|
||||
cy.getByTestId(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
@@ -81,21 +81,27 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
});
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Passed');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.getByTestId(proposalStatus, proposalTimeout)
|
||||
.should('have.text', 'Passed')
|
||||
.then(() => {
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Enacted'
|
||||
);
|
||||
});
|
||||
cy.getByTestId(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
cy.getByTestId(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
});
|
||||
@@ -109,15 +115,18 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.get(openProposals, { timeout: 6000 }).within(() => {
|
||||
cy.getByTestId(openProposals, { timeout: 6000 }).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
});
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
voteForProposal('for');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Enacted'
|
||||
);
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
|
||||
@@ -128,14 +137,17 @@ context(
|
||||
navigateTo(navigation.proposals);
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
.within(() => cy.getByTestId(viewProposalButton).click());
|
||||
});
|
||||
cy.get(proposalStatus).should('have.text', 'Open');
|
||||
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Declined');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
cy.getByTestId(proposalStatus, proposalTimeout).should(
|
||||
'have.text',
|
||||
'Declined'
|
||||
);
|
||||
getProposalInformationFromTable('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||
.and('be.visible');
|
||||
|
||||
@@ -32,24 +32,23 @@ import {
|
||||
import {
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
} from '../../support/wallet-functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||
|
||||
const vegaWalletStakedBalances =
|
||||
'[data-testid="vega-wallet-balance-staked-validators"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
|
||||
const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const rawProposalData = '[data-testid="proposal-data"]';
|
||||
const voteButtons = '[data-testid="vote-buttons"]';
|
||||
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
|
||||
const vegaWalletAssociatedBalance = 'associated-amount';
|
||||
const vegaWalletNameElement = 'wallet-name';
|
||||
const vegaWallet = 'vega-wallet';
|
||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||
const newProposalSubmitButton = 'proposal-submit';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const rawProposalData = 'proposal-data';
|
||||
const voteButtons = 'vote-buttons';
|
||||
const rejectProposalsLink = '[href="/proposals/rejected"]';
|
||||
const feedbackError = '[data-testid="Error"]';
|
||||
const noOpenProposals = '[data-testid="no-open-proposals"]';
|
||||
const noClosedProposals = '[data-testid="no-closed-proposals"]';
|
||||
const feedbackError = 'Error';
|
||||
const noOpenProposals = 'no-open-proposals';
|
||||
const noClosedProposals = 'no-closed-proposals';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
@@ -93,10 +92,10 @@ context(
|
||||
// Test can only pass if run before other proposal tests.
|
||||
it.skip('Should be able to see that no proposals exist', function () {
|
||||
// 3001-VOTE-003
|
||||
cy.get(noOpenProposals)
|
||||
cy.getByTestId(noOpenProposals)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'There are no open or yet to enact proposals');
|
||||
cy.get(noClosedProposals)
|
||||
cy.getByTestId(noClosedProposals)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'There are no enacted or rejected proposals');
|
||||
});
|
||||
@@ -126,11 +125,14 @@ context(
|
||||
stakingValidatorPageAddStake('2');
|
||||
closeStakingDialog();
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||
'contain',
|
||||
'2'
|
||||
);
|
||||
createRawProposal();
|
||||
});
|
||||
|
||||
it.skip('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
||||
it('Creating a proposal - proposal rejected - when closing time sooner than system default', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
|
||||
cy.get('input:invalid')
|
||||
@@ -138,7 +140,7 @@ context(
|
||||
.should('equal', 'Value must be greater than or equal to 1.');
|
||||
});
|
||||
|
||||
it.skip('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
||||
it('Creating a proposal - proposal rejected - when closing time later than system default', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
enterUniqueFreeFormProposalBody(
|
||||
'100000',
|
||||
@@ -168,7 +170,7 @@ context(
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.contains('Rejected').should('be.visible');
|
||||
cy.contains('Close time too late').should('be.visible');
|
||||
cy.get(viewProposalButton).click();
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('proposal-status').should('have.text', 'Rejected');
|
||||
@@ -185,14 +187,14 @@ context(
|
||||
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)';
|
||||
vegaWalletTeardown();
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
'0.00',
|
||||
txTimeout
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -205,7 +207,7 @@ context(
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -221,17 +223,17 @@ context(
|
||||
createTenDigitUnixTimeStampForSpecifiedDays(8);
|
||||
freeformProposal.unexpected = `i shouldn't be here`;
|
||||
const proposalPayload = JSON.stringify(freeformProposal);
|
||||
cy.get(rawProposalData).type(proposalPayload, {
|
||||
cy.getByTestId(rawProposalData).type(proposalPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
cy.get(rawProposalData)
|
||||
cy.getByTestId(rawProposalData)
|
||||
.invoke('val')
|
||||
.should('contain', "i shouldn't be here");
|
||||
});
|
||||
@@ -249,15 +251,15 @@ context(
|
||||
rawProposal.terms.unexpectedField = `i shouldn't be here`;
|
||||
const proposalPayload = JSON.stringify(rawProposal);
|
||||
|
||||
cy.get(rawProposalData).type(proposalPayload, {
|
||||
cy.getByTestId(rawProposalData).type(proposalPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
cy.get(feedbackError).should('have.text', errorMsg);
|
||||
cy.getByTestId(feedbackError).should('have.text', errorMsg);
|
||||
closeDialog();
|
||||
});
|
||||
|
||||
@@ -265,10 +267,10 @@ context(
|
||||
// 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 () {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.getByTestId('input-error-text').should('have.text', 'Required');
|
||||
cy.get(rawProposalData).type('Not a valid json string');
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId(rawProposalData).type('Not a valid json string');
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
cy.getByTestId('input-error-text').should(
|
||||
'have.text',
|
||||
'Must be valid JSON'
|
||||
@@ -283,22 +285,22 @@ context(
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
ethereumWalletConnect();
|
||||
stakingPageDisassociateTokens('0.0001');
|
||||
cy.get(vegaWallet)
|
||||
cy.getByTestId(vegaWallet)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'0.9999'
|
||||
);
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
cy.contains('Vote breakdown').should('be.visible', {
|
||||
timeout: 10000,
|
||||
});
|
||||
cy.get(voteButtons).should('not.exist');
|
||||
cy.getByTestId(voteButtons).should('not.exist');
|
||||
cy.getByTestId('min-proposal-requirements').should(
|
||||
'have.text',
|
||||
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
|
||||
@@ -311,20 +313,20 @@ context(
|
||||
cy.get('[data-testid="disconnect"]').click();
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
cy.getByTestId(viewProposalButton).click()
|
||||
);
|
||||
});
|
||||
// 3001-VOTE-075
|
||||
// 3001-VOTE-076
|
||||
cy.get(connectToVegaWalletButton)
|
||||
cy.getByTestId(connectToVegaWalletButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet')
|
||||
.click();
|
||||
cy.getByTestId('connector-jsonRpc').click();
|
||||
cy.get(vegaWalletNameElement).should('be.visible');
|
||||
cy.get(connectToVegaWalletButton).should('not.exist');
|
||||
cy.getByTestId(vegaWalletNameElement).should('be.visible');
|
||||
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
|
||||
// 3001-VOTE-100
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||
'1.00',
|
||||
txTimeout
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '../../support/common.functions';
|
||||
import {
|
||||
getDownloadedProposalJsonPath,
|
||||
getProposalFromTitle,
|
||||
submitUniqueRawProposal,
|
||||
} from '../../support/governance.functions';
|
||||
import {
|
||||
@@ -23,38 +24,38 @@ import {
|
||||
} from '../../support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import {
|
||||
switchVegaWalletPubKey,
|
||||
vegaWalletFaucetAssetsWithoutCheck,
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const proposalType = '[data-testid="proposal-type"]';
|
||||
const proposalDetails = '[data-testid="proposal-details"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
|
||||
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
|
||||
const newProposalTitle = '[data-testid="proposal-title"]';
|
||||
const newProposalDescription = '[data-testid="proposal-description"]';
|
||||
const newProposalTerms = '[data-testid="proposal-terms"]';
|
||||
const newProposedParameterValue =
|
||||
'[data-testid="selected-proposal-param-new-value"]';
|
||||
const minVoteDeadline = '[data-testid="min-vote"]';
|
||||
const maxVoteDeadline = '[data-testid="max-vote"]';
|
||||
const minValidationDeadline = '[data-testid="min-validation"]';
|
||||
const minEnactDeadline = '[data-testid="min-enactment"]';
|
||||
const maxEnactDeadline = '[data-testid="max-enactment"]';
|
||||
const inputError = '[data-testid="input-error-text"]';
|
||||
const enactmentDeadlineError =
|
||||
'[data-testid="enactment-before-voting-deadline"]';
|
||||
const proposalDownloadBtn = '[data-testid="proposal-download-json"]';
|
||||
const openProposals = 'open-proposals';
|
||||
const proposalType = 'proposal-type';
|
||||
const proposalDetails = 'proposal-details';
|
||||
const newProposalSubmitButton = 'proposal-submit';
|
||||
const proposalVoteDeadline = 'proposal-vote-deadline';
|
||||
const proposalParameterSelect = 'proposal-parameter-select';
|
||||
const proposalMarketSelect = 'proposal-market-select';
|
||||
const newProposalTitle = 'proposal-title';
|
||||
const newProposalDescription = 'proposal-description';
|
||||
const newProposalTerms = 'proposal-terms';
|
||||
const newProposedParameterValue = 'selected-proposal-param-new-value';
|
||||
const minVoteDeadline = 'min-vote';
|
||||
const maxVoteDeadline = 'max-vote';
|
||||
const minValidationDeadline = 'min-validation';
|
||||
const minEnactDeadline = 'min-enactment';
|
||||
const maxEnactDeadline = 'max-enactment';
|
||||
const inputError = 'input-error-text';
|
||||
const enactmentDeadlineError = 'enactment-before-voting-deadline';
|
||||
const proposalDownloadBtn = 'proposal-download-json';
|
||||
const feedbackError = '[data-testid="Error"]';
|
||||
const viewProposalBtn = 'view-proposal-btn';
|
||||
const liquidityVoteStatus = 'liquidity-votes-status';
|
||||
const tokenVoteStatus = 'token-votes-status';
|
||||
const proposalTermsSection = 'proposal';
|
||||
const proposalJsonToggle = 'proposal-json-toggle';
|
||||
const proposalJsonSection = 'proposal-json';
|
||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||
const fUSDCId =
|
||||
'816af99af60d684502a40824758f6b5377e6af48e50a9ee8ef478ecb879ea8bc';
|
||||
@@ -85,18 +86,20 @@ context(
|
||||
it('Unable to submit network parameter with missing/invalid fields', function () {
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.get(proposalDownloadBtn).click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.get(newProposalTitle).type(
|
||||
cy.getByTestId(proposalDownloadBtn).click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Invalid update network parameter proposal'
|
||||
);
|
||||
cy.get(newProposalDescription).type('E2E invalid test for proposals');
|
||||
cy.get(proposalParameterSelect).select(
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
'E2E invalid test for proposals'
|
||||
);
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
'spam_protection_proposal_min_tokens'
|
||||
);
|
||||
cy.get(newProposedParameterValue).type('0');
|
||||
cy.get(proposalVoteDeadline).clear().type('0');
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(newProposedParameterValue).type('0');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('0');
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wrap(
|
||||
@@ -106,7 +109,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON');
|
||||
});
|
||||
|
||||
@@ -114,29 +117,33 @@ context(
|
||||
it('Able to download and submit network param proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
// 3007-PNEC-006
|
||||
cy.get(newProposalTitle)
|
||||
cy.getByTestId(newProposalTitle)
|
||||
.siblings()
|
||||
.should('contain.text', '(100 characters or less)');
|
||||
// 3007-PNEC-004 3007-PNEC-005
|
||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update network parameter proposal'
|
||||
);
|
||||
// 3007-PNEC-009
|
||||
cy.get(newProposalDescription)
|
||||
cy.getByTestId(newProposalDescription)
|
||||
.siblings()
|
||||
.should('contain.text', '(20,000 characters or less)');
|
||||
// 3007-PNEC-007 3007-PNEC-008
|
||||
cy.get(newProposalDescription).type('E2E test for downloading proposals');
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
'E2E test for downloading proposals'
|
||||
);
|
||||
// 3007-PNEC-010
|
||||
cy.get(proposalParameterSelect).select(
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
'governance_proposal_asset_minClose'
|
||||
);
|
||||
// 3007-PNEC-011
|
||||
cy.get(newProposedParameterValue).type('10s');
|
||||
cy.getByTestId(newProposedParameterValue).type('10s');
|
||||
// 3007-PNEC-012
|
||||
cy.get(proposalVoteDeadline).clear().type('2');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('2');
|
||||
// 3007-PNEC-013 3007-PNEC-014
|
||||
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||
// 3007-PNEC-015
|
||||
cy.get(maxEnactDeadline).click();
|
||||
cy.getByTestId(maxEnactDeadline).click();
|
||||
// 3007-PNEC-016
|
||||
cy.getByTestId('enactment-date').invoke('text').should('not.be.empty');
|
||||
// 3007-PNEC-017
|
||||
@@ -145,7 +152,7 @@ context(
|
||||
).should('be.visible');
|
||||
// 3007-PNE-018
|
||||
cy.log('Download updated proposal file');
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -175,19 +182,21 @@ context(
|
||||
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
|
||||
navigateTo(navigation.proposals);
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||
cy.get(newProposalDescription).type('invalid deadlines');
|
||||
cy.get(proposalParameterSelect).select(
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update network parameter proposal'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('invalid deadlines');
|
||||
cy.getByTestId(proposalParameterSelect).select(
|
||||
'spam_protection_proposal_min_tokens'
|
||||
);
|
||||
cy.get(newProposedParameterValue).type('0');
|
||||
cy.get(proposalVoteDeadline).clear().type('0');
|
||||
cy.get(maxVoteDeadline).click();
|
||||
cy.get(enactmentDeadlineError).should(
|
||||
cy.getByTestId(newProposedParameterValue).type('0');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('0');
|
||||
cy.getByTestId(maxVoteDeadline).click();
|
||||
cy.getByTestId(enactmentDeadlineError).should(
|
||||
'have.text',
|
||||
'Proposal will fail if enactment is earlier than the voting deadline'
|
||||
'The proposal will fail if enactment is earlier than the voting deadline'
|
||||
);
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -198,55 +207,77 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).click();
|
||||
cy.getByTestId(newProposalSubmitButton).click();
|
||||
validateFeedBackMsg(
|
||||
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
||||
);
|
||||
});
|
||||
|
||||
// 3003-PMAN-001
|
||||
it('Able to submit valid new market proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.get(newProposalTitle).type('Test new market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wrap(
|
||||
getDownloadedProposalJsonPath('vega-new-market-proposal-')
|
||||
).then((filePath) => {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
submitUniqueRawProposal({ proposalBody: filePath }); // 3003-PMAN-003
|
||||
it(
|
||||
'Able to submit valid new market proposal',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
const proposalTitle = 'Test new market proposal';
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.getByTestId(newProposalTitle).type('Test new market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wrap(
|
||||
getDownloadedProposalJsonPath('vega-new-market-proposal-')
|
||||
).then((filePath) => {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
submitUniqueRawProposal({ proposalBody: filePath }); // 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');
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('Unable to submit new market proposal with missing/invalid fields', function () {
|
||||
const errorMsg =
|
||||
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.get(newProposalTitle).type('Test new market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
cy.getByTestId(newProposalTitle).type('Test new market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||
newMarketProposal.invalid = 'I am an invalid field';
|
||||
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -257,7 +288,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
validateFeedBackMsg(errorMsg);
|
||||
});
|
||||
@@ -265,21 +296,22 @@ context(
|
||||
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
||||
// 3002-PROP-022
|
||||
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||
cy.get('[data-testid="select-keypair-button"]').eq(0).click(); // switch to second wallet pub key
|
||||
switchVegaWalletPubKey();
|
||||
stakingPageAssociateTokens('1');
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update market proposal - rejected'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -290,14 +322,13 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
||||
closeDialog();
|
||||
ethereumWalletConnect();
|
||||
stakingPageDisassociateAllTokens();
|
||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
||||
switchVegaWalletPubKey();
|
||||
});
|
||||
|
||||
// 3002-PROP-020
|
||||
@@ -309,17 +340,19 @@ context(
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.getByTestId(newProposalTitle).type(
|
||||
'Test update market proposal - rejected'
|
||||
);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -330,7 +363,7 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||
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)'
|
||||
@@ -345,9 +378,9 @@ context(
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.get(newProposalTitle).type('Test update market proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.getByTestId(newProposalTitle).type('Test update market proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(proposalMarketSelect).select('Test market 1');
|
||||
cy.get('[data-testid="update-market-details"]').within(() => {
|
||||
cy.get('dd').eq(0).should('have.text', 'Test market 1');
|
||||
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
|
||||
@@ -362,12 +395,12 @@ context(
|
||||
});
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -414,19 +447,19 @@ context(
|
||||
it('Able to submit new asset proposal using min deadlines', function () {
|
||||
const proposalTitle = 'Test new asset proposal';
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.get(newProposalTitle).type(proposalTitle);
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(newProposalTitle).type(proposalTitle);
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
|
||||
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minValidationDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(minVoteDeadline).click();
|
||||
cy.getByTestId(minValidationDeadline).click();
|
||||
cy.getByTestId(minEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -437,9 +470,9 @@ context(
|
||||
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003
|
||||
});
|
||||
});
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
closeDialog();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
|
||||
// cannot submit a proposal with ERC20 address already in use
|
||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||
validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE');
|
||||
@@ -451,8 +484,8 @@ context(
|
||||
.within(() => {
|
||||
cy.getByTestId(viewProposalBtn).click();
|
||||
});
|
||||
cy.getByTestId('proposal-terms-toggle').click();
|
||||
cy.getByTestId(proposalTermsSection).within(() => {
|
||||
cy.getByTestId(proposalJsonToggle).click();
|
||||
cy.getByTestId(proposalJsonSection).within(() => {
|
||||
cy.contains('USDT Coin').should('be.visible');
|
||||
cy.contains('USDT').should('be.visible');
|
||||
});
|
||||
@@ -460,8 +493,8 @@ context(
|
||||
|
||||
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using min deadline', function () {
|
||||
@@ -470,9 +503,9 @@ context(
|
||||
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(minVoteDeadline).click();
|
||||
cy.getByTestId(minEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -484,13 +517,16 @@ context(
|
||||
});
|
||||
});
|
||||
navigateTo(navigation.proposals);
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalType)
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.getByTestId(proposalType)
|
||||
.contains('Update asset')
|
||||
.parentsUntil(proposalListItem)
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.get(proposalDetails).should('contain.text', assetId.slice(0, 6)); // 3001-VOTE-029
|
||||
cy.getByTestId(proposalDetails).should(
|
||||
'contain.text',
|
||||
assetId.slice(0, 6)
|
||||
); // 3001-VOTE-029
|
||||
cy.getByTestId(viewProposalBtn).click();
|
||||
});
|
||||
});
|
||||
@@ -498,13 +534,11 @@ context(
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
// 3001-VOTE-030 3001-VOTE-031
|
||||
cy.getByTestId('proposal-terms-toggle').click();
|
||||
cy.getByTestId('proposal-terms').within(() => {
|
||||
getProposalInformationFromTable('assetId').should('have.text', assetId);
|
||||
getProposalInformationFromTable('lifetimeLimit').should(
|
||||
'have.text',
|
||||
'10'
|
||||
);
|
||||
cy.getByTestId(proposalJsonToggle).click();
|
||||
cy.getByTestId(proposalJsonSection).within(() => {
|
||||
cy.contains(assetId).should('be.visible');
|
||||
cy.contains('lifetimeLimit').should('be.visible');
|
||||
cy.contains('10').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -512,9 +546,9 @@ context(
|
||||
it('Able to submit update asset proposal using max deadline', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.get(maxVoteDeadline).click();
|
||||
cy.get(maxEnactDeadline).click();
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(maxVoteDeadline).click();
|
||||
cy.getByTestId(maxEnactDeadline).click();
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -529,36 +563,36 @@ context(
|
||||
|
||||
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
cy.get(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.get(inputError).should('have.length', 3);
|
||||
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
|
||||
cy.getByTestId(inputError).should('have.length', 3);
|
||||
});
|
||||
|
||||
it('Able to download and submit freeform proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
// 3008-PFRO-006
|
||||
cy.get(newProposalTitle)
|
||||
cy.getByTestId(newProposalTitle)
|
||||
.siblings()
|
||||
.should('contain.text', '(100 characters or less)'); // 3008-PFRO-007
|
||||
// 3008-PFRO-005
|
||||
cy.get(newProposalTitle).type('Test freeform proposal form');
|
||||
cy.getByTestId(newProposalTitle).type('Test freeform proposal form');
|
||||
// 3008-PFRO-009
|
||||
cy.get(newProposalDescription)
|
||||
cy.getByTestId(newProposalDescription)
|
||||
.siblings()
|
||||
.should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010
|
||||
// 3008-PFRO-008 3002-PROP-012 3002-PROP-016
|
||||
cy.get(newProposalDescription).type(
|
||||
cy.getByTestId(newProposalDescription).type(
|
||||
'E2E test for downloading freeform proposal'
|
||||
);
|
||||
// 3008-PFRO-012
|
||||
cy.get(minVoteDeadline).should('exist'); // 3002-PROP-008
|
||||
cy.get(maxVoteDeadline).should('exist');
|
||||
cy.getByTestId(minVoteDeadline).should('exist'); // 3002-PROP-008
|
||||
cy.getByTestId(maxVoteDeadline).should('exist');
|
||||
// 3008-PFRO-011
|
||||
cy.get(proposalVoteDeadline).clear().type('2');
|
||||
cy.getByTestId(proposalVoteDeadline).clear().type('2');
|
||||
// 3008-PFRO-013 3008-PFRO-014
|
||||
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
|
||||
// 3008-PFRO-015
|
||||
cy.log('Download updated proposal file');
|
||||
cy.get(proposalDownloadBtn)
|
||||
cy.getByTestId(proposalDownloadBtn)
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.then(() => {
|
||||
@@ -592,15 +626,23 @@ context(
|
||||
}
|
||||
|
||||
function enterUpdateAssetProposalDetails() {
|
||||
cy.get(newProposalTitle).type('Test update asset proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.getByTestId(newProposalTitle).type('Test update asset proposal');
|
||||
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
|
||||
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
|
||||
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 2,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getMarketProposalDetailsFromTable(heading: string) {
|
||||
return cy
|
||||
.getByTestId('key-value-table-row')
|
||||
.contains(heading)
|
||||
.parent()
|
||||
.siblings();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -21,15 +21,15 @@ import {
|
||||
} from '../../support/governance.functions';
|
||||
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
|
||||
|
||||
const proposalListItem = 'proposals-list-item';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const openProposals = 'open-proposals';
|
||||
const voteStatus = 'vote-status';
|
||||
const proposalType = 'proposal-type';
|
||||
const proposalStatus = 'proposal-status';
|
||||
const proposalClosingDate = '[data-testid="vote-details"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const proposalClosingDate = 'vote-details';
|
||||
const viewProposalButton = 'view-proposal-btn';
|
||||
const voteBreakDownToggle = 'vote-breakdown-toggle';
|
||||
|
||||
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);
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalClosingDate)
|
||||
cy.getByTestId(openProposals).within(() => {
|
||||
cy.getByTestId(proposalClosingDate)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.should('match', /days|minutes/);
|
||||
cy.get(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.get(proposalClosingDate).last().should('contain.text', 'year');
|
||||
cy.getByTestId(proposalClosingDate).should('contain.text', 'months');
|
||||
cy.getByTestId(proposalClosingDate).last().should('contain.text', 'year');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
const proposalTitle = generateFreeFormProposalTitle();
|
||||
|
||||
submitUniqueRawProposal({ proposalTitle: proposalTitle });
|
||||
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
||||
cy.get('[data-testid="proposal-filter-toggle"]').click();
|
||||
cy.get('[data-testid="filter-input"]').type(proposerId);
|
||||
// cy.get(`#${proposalId}`).should('contain', proposalId);
|
||||
cy.contains(proposalTitle).should('be.visible');
|
||||
@@ -106,7 +106,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||
getProposalFromTitle(rawProposal.rationale.title).within(() => {
|
||||
cy.get(viewProposalButton).should('be.visible');
|
||||
cy.getByTestId(viewProposalButton).should('be.visible');
|
||||
cy.getByTestId(proposalType).should('have.text', 'Freeform');
|
||||
cy.getByTestId(proposalStatus).should('have.text', 'Open');
|
||||
});
|
||||
@@ -124,13 +124,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||
'have.text',
|
||||
'Participation not reached'
|
||||
);
|
||||
cy.get(viewProposalButton).click();
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
});
|
||||
voteForProposal('for');
|
||||
navigateTo(navigation.proposals);
|
||||
getProposalFromTitle(proposalTitle).within(() => {
|
||||
cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
|
||||
cy.get(viewProposalButton).click();
|
||||
cy.getByTestId(viewProposalButton).click();
|
||||
});
|
||||
cy.getByTestId(voteBreakDownToggle).click();
|
||||
getProposalInformationFromTable('Token participation met')
|
||||
|
||||
@@ -14,11 +14,10 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import {
|
||||
depositAsset,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
||||
const vegaWalletUnstakedBalance =
|
||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
|
||||
const rewardsTable = 'epoch-total-rewards-table';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const rewardsTimeOut = { timeout: 60000 };
|
||||
@@ -40,7 +39,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
||||
cy.associateTokensToVegaWallet('6000');
|
||||
navigateTo(navigation.validators);
|
||||
cy.VegaWalletTopUpRewardsPool();
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'6,000.0',
|
||||
txTimeout
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
verifyStakedBalance,
|
||||
verifyEthWalletTotalAssociatedBalance,
|
||||
verifyEthWalletAssociatedBalance,
|
||||
waitForSpinner,
|
||||
navigateTo,
|
||||
navigation,
|
||||
turnTelemetryOff,
|
||||
@@ -25,7 +24,7 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import {
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
} from '../../support/wallet-functions';
|
||||
const stakeValidatorListTotalStake = 'total-stake';
|
||||
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||
const stakeValidatorListStakePercentage = 'stake-percentage';
|
||||
@@ -54,12 +53,11 @@ context(
|
||||
'Staking Tab - with eth and vega wallets connected',
|
||||
{ tags: '@slow' },
|
||||
function () {
|
||||
// 2001-STKE-002, 2001-STKE-032
|
||||
// 1002-STKE-002, 1002-STKE-032
|
||||
before('visit staking tab and connect vega wallet', function () {
|
||||
cy.visit('/');
|
||||
ethereumWalletConnect();
|
||||
// this is a workaround for #2422 which can be removed once issue is resolved
|
||||
cy.associateTokensToVegaWallet('4');
|
||||
cy.connectVegaWallet();
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
});
|
||||
|
||||
@@ -69,33 +67,48 @@ context(
|
||||
function () {
|
||||
cy.clearLocalStorage();
|
||||
turnTelemetryOff();
|
||||
cy.reload();
|
||||
waitForSpinner();
|
||||
cy.connectVegaWallet();
|
||||
ethereumWalletConnect();
|
||||
// Go to homepage to allow wallet teardown without epoch timer refreshing page
|
||||
navigateTo(navigation.home);
|
||||
vegaWalletTeardown();
|
||||
navigateTo(navigation.validators);
|
||||
}
|
||||
);
|
||||
|
||||
// 1002-STKE-035 1002-STKE-036
|
||||
it('Unable to stake against a validator with less than minimum and more than associated amount', function () {
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||
verifyEthWalletAssociatedBalance('3.0');
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
clickOnValidatorFromList(0);
|
||||
cy.getByTestId(stakeAddStakeRadioButton, epochTimeout).click({
|
||||
force: true,
|
||||
});
|
||||
cy.getByTestId(stakeTokenAmountInputBox).type('0.001');
|
||||
cy.getByTestId(stakeTokenSubmitButton).should('be.disabled');
|
||||
cy.getByTestId(stakeTokenAmountInputBox).clear().type('4');
|
||||
cy.getByTestId(stakeTokenSubmitButton).should('be.disabled');
|
||||
});
|
||||
it('Able to stake against a validator - using vega from wallet', function () {
|
||||
ensureSpecifiedUnstakedTokensAreAssociated('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||
verifyEthWalletAssociatedBalance('3.0');
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
// 2001-STKE-031
|
||||
// 1002-STKE-031
|
||||
clickOnValidatorFromList(0);
|
||||
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
|
||||
// 1002-STKE-033, 1002-STKE-034, 1002-STKE-037
|
||||
stakingValidatorPageAddStake('2');
|
||||
verifyUnstakedBalance(1.0);
|
||||
// 2001-STKE-039
|
||||
// 1002-STKE-039
|
||||
verifyStakedBalance(2.0);
|
||||
verifyNextEpochValue(2.0); // 2001-STKE-016 2001-STKE-038
|
||||
verifyThisEpochValue(2.0); // 2001-STKE-013
|
||||
verifyNextEpochValue(2.0); // 1002-STKE-016 1002-STKE-038
|
||||
verifyThisEpochValue(2.0); // 1002-STKE-013
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
|
||||
// 2002-SINC-007
|
||||
// 2002-SINC-007 1002-STKE-015 1002-STKE-017 1002-STKE-052
|
||||
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
|
||||
});
|
||||
|
||||
@@ -114,6 +127,7 @@ context(
|
||||
cy.getByTestId('staked-by-user-tooltip')
|
||||
.first()
|
||||
.should('have.text', 'Staked by me: 2.00');
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-pending-stake').first().realHover();
|
||||
cy.getByTestId('pending-user-stake-tooltip')
|
||||
.first()
|
||||
@@ -218,7 +232,7 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
// 2001-STKE-041
|
||||
// 1002-STKE-041 1002-STKE-053
|
||||
it(
|
||||
'Able to remove part of a stake against a validator',
|
||||
{ tags: '@smoke' },
|
||||
@@ -231,11 +245,11 @@ context(
|
||||
verifyUnstakedBalance(1.0);
|
||||
closeStakingDialog();
|
||||
navigateTo(navigation.validators);
|
||||
// 2001-STKE-040
|
||||
// 1002-STKE-040
|
||||
clickOnValidatorFromList(0);
|
||||
// 2001-STKE-044, 2001-STKE-048
|
||||
// 1002-STKE-044, 1002-STKE-048
|
||||
stakingValidatorPageRemoveStake('1');
|
||||
// 2001-STKE-049
|
||||
// 1002-STKE-049
|
||||
verifyNextEpochValue(2.0);
|
||||
verifyUnstakedBalance(2.0);
|
||||
verifyStakedBalance(2.0);
|
||||
@@ -255,7 +269,7 @@ context(
|
||||
}
|
||||
);
|
||||
|
||||
// 2001-STKE-045
|
||||
// 1002-STKE-045
|
||||
it('Able to remove a full stake against a validator', function () {
|
||||
stakingPageAssociateTokens('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
@@ -303,6 +317,7 @@ context(
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 1002-STKE-046 1002-STKE-047
|
||||
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
|
||||
stakingPageAssociateTokens('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
@@ -381,6 +396,9 @@ context(
|
||||
|
||||
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
||||
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||
cy.reload();
|
||||
ethereumWalletConnect();
|
||||
cy.connectVegaWallet();
|
||||
stakingPageAssociateTokens('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -403,7 +421,7 @@ context(
|
||||
});
|
||||
|
||||
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||
// 2001-STKE-004
|
||||
// 1002-STKE-004
|
||||
stakingPageAssociateTokens('3');
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -417,7 +435,7 @@ context(
|
||||
});
|
||||
|
||||
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||
// 2001-STKE-004
|
||||
// 1002-STKE-004
|
||||
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -431,7 +449,7 @@ context(
|
||||
});
|
||||
|
||||
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
|
||||
// 2001-STKE-004
|
||||
// 1002-STKE-004
|
||||
stakingPageAssociateTokens('3', { type: 'wallet' });
|
||||
verifyUnstakedBalance(3.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -445,7 +463,7 @@ context(
|
||||
});
|
||||
|
||||
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
|
||||
// 2001-STKE-004
|
||||
// 1002-STKE-004
|
||||
stakingPageAssociateTokens('6');
|
||||
verifyUnstakedBalance(6.0);
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
@@ -486,11 +504,6 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
afterEach('Teardown Wallet', function () {
|
||||
navigateTo(navigation.home);
|
||||
vegaWalletTeardown();
|
||||
});
|
||||
|
||||
function verifyNextEpochValue(amount: number) {
|
||||
cy.getByTestId('stake-next-epoch', epochTimeout)
|
||||
.contains(amount, epochTimeout)
|
||||
@@ -498,7 +511,7 @@ context(
|
||||
}
|
||||
|
||||
function verifyThisEpochValue(amount: number) {
|
||||
cy.getByTestId('stake-this-epoch', epochTimeout) // 2001-STKE-013
|
||||
cy.getByTestId('stake-this-epoch', epochTimeout) // 1002-STKE-013
|
||||
.contains(amount, epochTimeout)
|
||||
.should('be.visible');
|
||||
}
|
||||
|
||||
@@ -14,31 +14,31 @@ import {
|
||||
} from '../../support/staking.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import {
|
||||
switchVegaWalletPubKey,
|
||||
vegaWalletAssociate,
|
||||
vegaWalletDisassociate,
|
||||
vegaWalletSetSpecifiedApprovalAmount,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-teardown.functions';
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletUnstakedBalance =
|
||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||
const ethWalletContainer = 'ethereum-wallet';
|
||||
const vegaWalletAssociatedBalance = 'currency-value';
|
||||
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
|
||||
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 associateWalletRadioButton = 'associate-radio-wallet';
|
||||
const tokenAmountInputBox = 'token-amount-input';
|
||||
const tokenSubmitButton = '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 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');
|
||||
|
||||
context(
|
||||
'Token association flow - with eth and vega wallets connected',
|
||||
@@ -64,31 +64,41 @@ context(
|
||||
}
|
||||
);
|
||||
|
||||
it('Able to associate tokens - from wallet', function () {
|
||||
//1004-ASSO-003
|
||||
//1004-ASSO-005
|
||||
//1004-ASSO-009
|
||||
//1004-ASSO-030
|
||||
//1004-ASSO-012
|
||||
//1004-ASSO-013
|
||||
//1004-ASSO-014
|
||||
//1004-ASSO-015
|
||||
//1004-ASSO-030
|
||||
//0005-ETXN-006
|
||||
//0005-ETXN-003
|
||||
//0005-ETXN-005
|
||||
stakingPageAssociateTokens('2', { skipConfirmation: true });
|
||||
validateWalletCurrency('Associated', '0.00');
|
||||
validateWalletCurrency('Pending association', '2.00');
|
||||
validateWalletCurrency('Total associated after pending', '2.00');
|
||||
// 0005-ETXN-002
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
});
|
||||
it(
|
||||
'Able to associate tokens - from wallet',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
//1004-ASSO-003
|
||||
//1004-ASSO-005
|
||||
//1004-ASSO-009
|
||||
//1004-ASSO-030
|
||||
//1004-ASSO-012
|
||||
//1004-ASSO-013
|
||||
//1004-ASSO-014
|
||||
//1004-ASSO-015
|
||||
//1004-ASSO-030
|
||||
//0005-ETXN-006
|
||||
//0005-ETXN-003
|
||||
//0005-ETXN-005
|
||||
stakingPageAssociateTokens('2', { skipConfirmation: true });
|
||||
validateWalletCurrency('Associated', '0.00');
|
||||
validateWalletCurrency('Pending association', '2.00');
|
||||
validateWalletCurrency('Total associated after pending', '2.00');
|
||||
// 0005-ETXN-002
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it('Able to disassociate all associated tokens - manually', function () {
|
||||
// 1004-ASSO-025
|
||||
@@ -119,7 +129,7 @@ context(
|
||||
verifyEthWalletAssociatedBalance('1,001.00');
|
||||
verifyEthWalletTotalAssociatedBalance('7,001.00');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
'1,001.00'
|
||||
);
|
||||
@@ -129,14 +139,20 @@ context(
|
||||
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
stakingPageDisassociateTokens('1');
|
||||
verifyEthWalletAssociatedBalance('1.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
1.0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -146,21 +162,24 @@ 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.';
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
cy.get(ethWalletDissociateButton).click();
|
||||
cy.get(disassociationWarning).should('contain', warningText);
|
||||
cy.getByTestId(disassociationWarning).should('contain', warningText);
|
||||
stakingPageDisassociateAllTokens();
|
||||
cy.get(ethWalletContainer)
|
||||
cy.getByTestId(ethWalletContainer)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||
'not.exist'
|
||||
);
|
||||
});
|
||||
cy.get(ethWalletContainer)
|
||||
cy.getByTestId(ethWalletContainer)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||
@@ -168,7 +187,10 @@ context(
|
||||
);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
0.0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -190,9 +212,15 @@ context(
|
||||
verifyEthWalletAssociatedBalance('2.0');
|
||||
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
stakingPageDisassociateTokens('1', {
|
||||
type: 'contract',
|
||||
skipConfirmation: true,
|
||||
@@ -213,45 +241,54 @@ context(
|
||||
cy.get('button').contains('Select a validator to nominate').click();
|
||||
cy.getByTestId('epoch-countdown').should('be.visible');
|
||||
stakingPageAssociateTokens('37', { type: 'contract' });
|
||||
cy.get(vestingContractSection)
|
||||
cy.getByTestId(vestingContractSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(associatedKey).should(
|
||||
cy.getByTestId(associatedKey).should(
|
||||
'contain',
|
||||
Cypress.env('vegaWalletPublicKeyShort')
|
||||
);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 37);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 37);
|
||||
});
|
||||
cy.get(vegaInWalletSection)
|
||||
cy.getByTestId(vegaInWalletSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(associatedKey).should(
|
||||
cy.getByTestId(associatedKey).should(
|
||||
'contain',
|
||||
Cypress.env('vegaWalletPublicKeyShort')
|
||||
);
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 21);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
58
|
||||
);
|
||||
});
|
||||
stakingPageDisassociateTokens('6', { type: 'contract' });
|
||||
cy.get(vestingContractSection)
|
||||
cy.getByTestId(vestingContractSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 31);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
52
|
||||
);
|
||||
});
|
||||
navigateTo(navigation.validators);
|
||||
stakingPageDisassociateTokens('9', { type: 'wallet' });
|
||||
cy.get(vegaInWalletSection)
|
||||
cy.getByTestId(vegaInWalletSection)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
||||
cy.getByTestId(associatedAmount, txTimeout).should('contain', 12);
|
||||
});
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
43
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -260,10 +297,10 @@ context(
|
||||
// 1004-ASSO-010
|
||||
// No warning visible as described in AC, but the button is disabled
|
||||
cy.get(ethWalletAssociateButton).click();
|
||||
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
||||
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
|
||||
cy.getByTestId(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
||||
cy.getByTestId(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
|
||||
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled');
|
||||
});
|
||||
|
||||
// 1004-ASSO-004
|
||||
@@ -288,23 +325,25 @@ context(
|
||||
|
||||
it('Able to associate tokens to different public key of connected vega wallet', function () {
|
||||
cy.get(ethWalletAssociateButton).click();
|
||||
cy.get(associateWalletRadioButton).click();
|
||||
cy.get(connectedVegaKey).should(
|
||||
cy.getByTestId(associateWalletRadioButton).click();
|
||||
cy.getByTestId(connectedVegaKey).should(
|
||||
'have.text',
|
||||
Cypress.env('vegaWalletPublicKey')
|
||||
);
|
||||
|
||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
||||
cy.get(connectedVegaKey).should(
|
||||
switchVegaWalletPubKey();
|
||||
cy.getByTestId(connectedVegaKey).should(
|
||||
'have.text',
|
||||
Cypress.env('vegaWalletPublicKey2')
|
||||
);
|
||||
stakingPageAssociateTokens('2');
|
||||
cy.get(vegaWallet).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||
'contain',
|
||||
2.0
|
||||
);
|
||||
});
|
||||
cy.get(associateCompleteText).should(
|
||||
cy.getByTestId(associateCompleteText).should(
|
||||
'have.text',
|
||||
`Vega key ${Cypress.env(
|
||||
'vegaWalletPublicKey2Short'
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
waitForSpinner,
|
||||
} from '../../support/common.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
import { depositAsset } from '../../support/wallet-teardown.functions';
|
||||
import { depositAsset } from '../../support/wallet-functions';
|
||||
|
||||
const withdraw = 'withdraw';
|
||||
const withdrawalForm = 'withdraw-form';
|
||||
@@ -55,6 +55,10 @@ context(
|
||||
navigateTo(navigation.withdraw);
|
||||
cy.connectVegaWallet();
|
||||
ethereumWalletConnect();
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'contain.text',
|
||||
usdtName
|
||||
);
|
||||
});
|
||||
|
||||
it('Able to open withdrawal form with vega wallet connected', function () {
|
||||
@@ -69,7 +73,10 @@ context(
|
||||
it('Unable to submit withdrawal with invalid fields', function () {
|
||||
cy.getByTestId(withdraw).should('be.visible').click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.get('select').select(usdtSelectValue, { force: true });
|
||||
cy.getByTestId('select-asset').click();
|
||||
cy.get('select')
|
||||
.select(usdtSelectValue, { force: true })
|
||||
.should('have.value', usdtSelectValue);
|
||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
cy.getByTestId(formValidationError).should('have.length', 1);
|
||||
@@ -89,68 +96,75 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
|
||||
// fill in withdrawal form
|
||||
cy.getByTestId(withdraw).should('be.visible').click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.get('select').select(usdtSelectValue, { force: true });
|
||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||
cy.getByTestId(withdrawalThreshold).should(
|
||||
'have.text',
|
||||
'100,000.00000T'
|
||||
);
|
||||
cy.getByTestId(delayTime).should('have.text', 'None');
|
||||
cy.getByTestId(amountInput).click().type('120');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
// assert withdrawal request
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
cy.getByTestId(toastPanel).should(
|
||||
'contain.text',
|
||||
'Withdraw 120.00 tUSDC'
|
||||
it(
|
||||
'Able to withdraw asset: -eth wallet connected -withdraw funds button',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
// fill in withdrawal form
|
||||
cy.getByTestId(withdraw).should('be.visible').click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.getByTestId('select-asset').click();
|
||||
cy.get('select')
|
||||
.select(usdtSelectValue, { force: true })
|
||||
.should('have.value', usdtSelectValue);
|
||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||
cy.getByTestId(withdrawalThreshold).should(
|
||||
'have.text',
|
||||
'100,000.00000T'
|
||||
);
|
||||
cy.getByTestId(toastCompleteWithdrawal).click();
|
||||
cy.getByTestId(toastClose).click();
|
||||
cy.getByTestId(delayTime).should('have.text', 'None');
|
||||
cy.getByTestId(amountInput).click().type('120');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
});
|
||||
// withdrawal complete
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'The withdrawal has been approved.')
|
||||
.within(() => {
|
||||
cy.getByTestId(toastPanel).should(
|
||||
'contain.text',
|
||||
'Withdraw 120.00 tUSDC'
|
||||
);
|
||||
});
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
.should('contain.text', 'Transaction confirmed')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
// withdrawal history for complete withdrawal displayed
|
||||
cy.get(tableWithdrawnStatus)
|
||||
.eq(1, txTimeout)
|
||||
.should('have.text', 'Completed')
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '120.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableWithdrawnTimeStamp).should('not.be.empty');
|
||||
cy.get(tableTxHash)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/tx/');
|
||||
});
|
||||
});
|
||||
// assert withdrawal request
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'Funds unlocked')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
cy.getByTestId(toastPanel).should(
|
||||
'contain.text',
|
||||
'Withdraw 120.00 tUSDC'
|
||||
);
|
||||
cy.getByTestId(toastCompleteWithdrawal).click();
|
||||
cy.getByTestId(toastClose).click();
|
||||
});
|
||||
// withdrawal complete
|
||||
cy.getByTestId(toast)
|
||||
.first(txTimeout)
|
||||
.should('contain.text', 'The withdrawal has been approved.')
|
||||
.within(() => {
|
||||
cy.getByTestId(toastPanel).should(
|
||||
'contain.text',
|
||||
'Withdraw 120.00 tUSDC'
|
||||
);
|
||||
});
|
||||
cy.getByTestId(toast)
|
||||
.last(txTimeout)
|
||||
.should('contain.text', 'Transaction confirmed')
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link').should('exist');
|
||||
});
|
||||
// withdrawal history for complete withdrawal displayed
|
||||
cy.get(tableWithdrawnStatus)
|
||||
.eq(1, txTimeout)
|
||||
.should('have.text', 'Completed')
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get(tableAssetSymbol).should('have.text', usdcSymbol);
|
||||
cy.get(tableAmount).should('have.text', '120.00');
|
||||
cy.get(tableReceiverAddress)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/address/');
|
||||
cy.get(tableWithdrawnTimeStamp).should('not.be.empty');
|
||||
cy.get(tableTxHash)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://sepolia.etherscan.io/tx/');
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('Able to withdraw asset: -eth wallet not connected', function () {
|
||||
const ethWalletAddress = Cypress.env('ethWalletPublicKey');
|
||||
@@ -159,7 +173,10 @@ context(
|
||||
// fill in withdrawal form
|
||||
cy.getByTestId(withdraw).should('be.visible').click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.get('select').select(usdtSelectValue, { force: true });
|
||||
cy.getByTestId('select-asset').click();
|
||||
cy.get('select')
|
||||
.select(usdtSelectValue, { force: true })
|
||||
.should('have.value', usdtSelectValue);
|
||||
cy.getByTestId(ethAddressInput).should('be.empty');
|
||||
cy.getByTestId(amountInput).click().type('110');
|
||||
cy.getByTestId(submitWithdrawalButton).click();
|
||||
@@ -219,7 +236,10 @@ context(
|
||||
it('Should be able to see withdrawal details from toast', function () {
|
||||
cy.getByTestId(withdraw).click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.get('select').select(usdtSelectValue, { force: true });
|
||||
cy.getByTestId('select-asset').click();
|
||||
cy.get('select')
|
||||
.select(usdtSelectValue, { force: true })
|
||||
.should('have.value', usdtSelectValue);
|
||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||
cy.getByTestId(withdrawalThreshold).should(
|
||||
'have.text',
|
||||
@@ -274,7 +294,10 @@ context(
|
||||
cy.connectPublicKey(vegaWalletPubKey);
|
||||
cy.getByTestId(withdraw).should('be.visible').click();
|
||||
cy.getByTestId(withdrawalForm, txTimeout).within(() => {
|
||||
cy.get('select').select(usdtSelectValue, { force: true });
|
||||
cy.getByTestId('select-asset').click();
|
||||
cy.get('select')
|
||||
.select(usdtSelectValue, { force: true })
|
||||
.should('have.value', usdtSelectValue);
|
||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||
cy.getByTestId(amountInput).click().type('100');
|
||||
cy.pause();
|
||||
|
||||
@@ -10,9 +10,10 @@ import {
|
||||
} from '../../support/governance.functions';
|
||||
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
|
||||
|
||||
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
|
||||
const proposalDocsLink = 'proposal-docs-link';
|
||||
const proposalDocumentationLink = 'proposal-documentation-link';
|
||||
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
|
||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
|
||||
context(
|
||||
'Governance Page - verify elements on page',
|
||||
@@ -41,7 +42,7 @@ context(
|
||||
|
||||
it('should be able to see a working link for - find out more about Vega governance', function () {
|
||||
// 3001-VOTE-001
|
||||
cy.get(proposalDocumentationLink)
|
||||
cy.getByTestId(proposalDocumentationLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Find out more about Vega governance')
|
||||
.and('have.attr', 'href')
|
||||
@@ -64,7 +65,7 @@ context(
|
||||
// 3007-PNE-021
|
||||
it('should have documentation links for network parameter proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/network-parameter-proposal');
|
||||
@@ -73,7 +74,7 @@ context(
|
||||
// 3003-PMAN-002 3003-PMAN-005
|
||||
it('should have documentation links for new market proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/new-market-proposal');
|
||||
@@ -82,7 +83,7 @@ context(
|
||||
// 3004-PMAC-005
|
||||
it('should have documentation links for update market proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/update-market-proposal');
|
||||
@@ -91,7 +92,7 @@ context(
|
||||
// 3005-PASN-002 005-PASN-005
|
||||
it('should have documentation links for new asset proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/new-asset-proposal');
|
||||
@@ -100,7 +101,7 @@ context(
|
||||
// 3006-PASC-002 3006-PASC-005
|
||||
it('should have documentation links for update asset proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/update-asset-proposal');
|
||||
@@ -109,7 +110,7 @@ context(
|
||||
// 3008-PFRO-003 3008-PFRO-017
|
||||
it('should have documentation links for freeform proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||
cy.getByTestId('proposal-docs-link')
|
||||
cy.getByTestId(proposalDocsLink)
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/tutorials/proposals/freeform-proposal');
|
||||
@@ -117,7 +118,7 @@ context(
|
||||
|
||||
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
|
||||
goToMakeNewProposal(governanceProposalType.RAW);
|
||||
cy.get(connectToVegaWalletButton)
|
||||
cy.getByTestId(connectToVegaWalletButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
});
|
||||
@@ -165,6 +166,7 @@ context(
|
||||
);
|
||||
});
|
||||
});
|
||||
cy.get('[data-testid="closed-proposals-toggle-networkUpgrades"]').click();
|
||||
cy.getByTestId('closed-proposals').within(() => {
|
||||
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
|
||||
'have.length',
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
goToMakeNewProposal,
|
||||
governanceProposalType,
|
||||
} from '../../support/governance.functions';
|
||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-functions';
|
||||
|
||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
|
||||
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
} from '../../support/common.functions';
|
||||
import { waitForBeginningOfEpoch } from '../../support/staking.functions';
|
||||
|
||||
const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
|
||||
const warning = '[data-testid="callout"]';
|
||||
const viewToggle = 'epoch-reward-view-toggle-total';
|
||||
const warning = 'callout';
|
||||
|
||||
context(
|
||||
'Rewards Page - verify elements on page',
|
||||
@@ -27,7 +27,7 @@ context(
|
||||
});
|
||||
|
||||
it('should have epoch warning', function () {
|
||||
cy.get(warning)
|
||||
cy.getByTestId(warning)
|
||||
.should('be.visible')
|
||||
.and(
|
||||
'have.text',
|
||||
@@ -36,7 +36,7 @@ context(
|
||||
});
|
||||
|
||||
it('should have toggle for seeing total vs individual rewards', function () {
|
||||
cy.get(viewToggle).should('be.visible');
|
||||
cy.getByTestId(viewToggle).should('be.visible');
|
||||
});
|
||||
|
||||
// Skipping due to bug #3471 causing flaky failuress
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { navigateTo, navigation } from '../../support/common.functions';
|
||||
|
||||
const tokenDetailsTable = '.token-details';
|
||||
const address = '[data-testid="token-address"]';
|
||||
const contract = '[data-testid="token-contract"]';
|
||||
const totalSupply = '[data-testid="total-supply"]';
|
||||
const circulatingSupply = '[data-testid="circulating-supply"]';
|
||||
const staked = '[data-testid="staked"]';
|
||||
const tranchesLink = '[data-testid="tranches-link"]';
|
||||
const redeemBtn = '[data-testid="check-vesting-page-btn"]';
|
||||
const getVegaWalletLink = '[data-testid="get-vega-wallet-link"]';
|
||||
const associateVegaLink =
|
||||
'[data-testid="associate-vega-tokens-link-on-homepage"]';
|
||||
const stakingBtn = '[data-testid="staking-button-on-homepage"]';
|
||||
const governanceBtn = '[data-testid="governance-button-on-homepage"]';
|
||||
const address = 'token-address';
|
||||
const contract = 'token-contract';
|
||||
const totalSupply = 'total-supply';
|
||||
const circulatingSupply = 'circulating-supply';
|
||||
const staked = 'staked';
|
||||
const tranchesLink = 'tranches-link';
|
||||
const redeemBtn = 'check-vesting-page-btn';
|
||||
const getVegaWalletLink = 'get-vega-wallet-link';
|
||||
const associateVegaLink = 'associate-vega-tokens-link-on-homepage';
|
||||
const stakingBtn = 'staking-button-on-homepage';
|
||||
const governanceBtn = 'governance-button-on-homepage';
|
||||
|
||||
const vegaTokenAddress = Cypress.env('vegaTokenAddress');
|
||||
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
||||
@@ -25,7 +24,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
describe('THE $VEGA TOKEN table', function () {
|
||||
it('should have TOKEN ADDRESS', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.get(address)
|
||||
cy.getByTestId(address)
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.should('be.equal', vegaTokenAddress);
|
||||
@@ -34,7 +33,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
it('should have VESTING CONTRACT', function () {
|
||||
// 1004-ASSO-001
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.get(contract)
|
||||
cy.getByTestId(contract)
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.should('be.equal', vegaTokenContractAddress);
|
||||
@@ -42,56 +41,56 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||
});
|
||||
it('should have TOTAL SUPPLY', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.get(totalSupply).should('be.visible');
|
||||
cy.getByTestId(totalSupply).should('be.visible');
|
||||
});
|
||||
});
|
||||
it('should have CIRCULATING SUPPLY', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.get(circulatingSupply).should('be.visible');
|
||||
cy.getByTestId(circulatingSupply).should('be.visible');
|
||||
});
|
||||
});
|
||||
it('should have STAKED $VEGA', function () {
|
||||
cy.get(tokenDetailsTable).within(() => {
|
||||
cy.get(staked).should('be.visible');
|
||||
cy.getByTestId(staked).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('links and buttons', function () {
|
||||
it('should have TRANCHES link', function () {
|
||||
cy.get(tranchesLink)
|
||||
cy.getByTestId(tranchesLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', '/token/tranches');
|
||||
});
|
||||
it('should have REDEEM button', function () {
|
||||
cy.get(redeemBtn)
|
||||
cy.getByTestId(redeemBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
.and('equal', '/token/redeem');
|
||||
});
|
||||
it('should have GET VEGA WALLET link', function () {
|
||||
cy.get(getVegaWalletLink)
|
||||
cy.getByTestId(getVegaWalletLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', 'https://vega.xyz/wallet');
|
||||
});
|
||||
it('should have ASSOCIATE VEGA TOKENS link', function () {
|
||||
cy.get(associateVegaLink)
|
||||
cy.getByTestId(associateVegaLink)
|
||||
.should('be.visible')
|
||||
.and('have.attr', 'href')
|
||||
.and('equal', '/token/associate');
|
||||
});
|
||||
it('should have STAKING button', function () {
|
||||
cy.get(stakingBtn)
|
||||
cy.getByTestId(stakingBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
.and('equal', '/validators');
|
||||
});
|
||||
it('should have GOVERNANCE button', function () {
|
||||
cy.get(governanceBtn)
|
||||
cy.getByTestId(governanceBtn)
|
||||
.should('be.visible')
|
||||
.parent()
|
||||
.should('have.attr', 'href')
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import {
|
||||
navigation,
|
||||
verifyPageHeader,
|
||||
verifyTabHighlighted,
|
||||
} from '../../support/common.functions';
|
||||
import { clickOnValidatorFromList } from '../../support/staking.functions';
|
||||
import {
|
||||
clickOnValidatorFromList,
|
||||
waitForBeginningOfEpoch,
|
||||
} from '../../support/staking.functions';
|
||||
import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
|
||||
|
||||
const guideLink = '[data-testid="staking-guide-link"]';
|
||||
const validatorTitle = '[data-testid="validator-node-title"]';
|
||||
const validatorId = '[data-testid="validator-id"]';
|
||||
const validatorPubKey = '[data-testid="validator-public-key"]';
|
||||
const ethAddressLink = '[data-testid="link"]';
|
||||
const validatorStatus = '[data-testid="validator-status"]';
|
||||
const totalStake = '[data-testid="total-stake"]';
|
||||
const pendingStake = '[data-testid="pending-stake"]';
|
||||
const stakedByOperator = '[data-testid="staked-by-operator"]';
|
||||
const stakedByDelegates = '[data-testid="staked-by-delegates"]';
|
||||
const stakeShare = '[data-testid="stake-percentage"]';
|
||||
const stakedByOperatorToolTip = '[data-testid="staked-operator-tooltip"]';
|
||||
const stakedByDelegatesToolTip = '[data-testid="staked-delegates-tooltip"]';
|
||||
const totalStakedToolTip = '[data-testid="total-staked-tooltip"]';
|
||||
const unnormalisedVotingPowerToolTip =
|
||||
'[data-testid="unnormalised-voting-power-tooltip"]';
|
||||
const normalisedVotingPowerToolTip =
|
||||
'[data-testid="normalised-voting-power-tooltip"]';
|
||||
const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
|
||||
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
|
||||
const totalPenaltyToolTip = '[data-testid="total-penalty-tooltip"]';
|
||||
const epochCountDown = '[data-testid="epoch-countdown"]';
|
||||
const guideLink = 'staking-guide-link';
|
||||
const validatorTitle = 'validator-node-title';
|
||||
const validatorId = 'validator-id';
|
||||
const validatorPubKey = 'validator-public-key';
|
||||
const ethAddressLink = 'link';
|
||||
const validatorStatus = 'validator-status';
|
||||
const totalStake = 'total-stake';
|
||||
const pendingStake = 'pending-stake';
|
||||
const stakedByOperator = 'staked-by-operator';
|
||||
const stakedByDelegates = 'staked-by-delegates';
|
||||
const stakeShare = 'stake-percentage';
|
||||
const stakedByOperatorToolTip = 'staked-operator-tooltip';
|
||||
const stakedByDelegatesToolTip = 'staked-delegates-tooltip';
|
||||
const totalStakedToolTip = 'total-staked-tooltip';
|
||||
const unnormalisedVotingPowerToolTip = 'unnormalised-voting-power-tooltip';
|
||||
const normalisedVotingPowerToolTip = 'normalised-voting-power-tooltip';
|
||||
const performancePenaltyToolTip = 'performance-penalty-tooltip';
|
||||
const overstakedPenaltyToolTip = 'overstaked-penalty-tooltip';
|
||||
const multisigPenaltyToolTip = 'multisig-error-tooltip';
|
||||
const epochCountDown = 'epoch-countdown';
|
||||
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
|
||||
|
||||
context('Validators Page - verify elements on page', function () {
|
||||
@@ -37,206 +40,232 @@ context('Validators Page - verify elements on page', function () {
|
||||
});
|
||||
|
||||
describe('with wallets disconnected', { tags: '@smoke' }, function () {
|
||||
describe('description section', function () {
|
||||
it('Should have validators tab highlighted', function () {
|
||||
verifyTabHighlighted(navigation.validators);
|
||||
});
|
||||
|
||||
it('Should have validators ON VEGA header visible', function () {
|
||||
verifyPageHeader('Validators');
|
||||
});
|
||||
|
||||
it('Should have Staking Guide link visible', function () {
|
||||
// 2001-STKE-003
|
||||
cy.get(guideLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Read more about staking on Vega')
|
||||
.and(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega'
|
||||
);
|
||||
});
|
||||
it('Should have validators tab highlighted', function () {
|
||||
verifyTabHighlighted(navigation.validators);
|
||||
});
|
||||
describe(
|
||||
'Should be able to see validator list from the staking page',
|
||||
{ tags: '@regression' },
|
||||
function () {
|
||||
// 2001-STKE-050
|
||||
it('Should be able to see validator names', function () {
|
||||
cy.get('[col-id="validator"] > div > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($name) => {
|
||||
cy.wrap($name).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake', function () {
|
||||
cy.getByTestId('total-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stake) => {
|
||||
cy.wrap($stake).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
it('Should have validators ON VEGA header visible', function () {
|
||||
verifyPageHeader('Validators');
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake tooltip', function () {
|
||||
cy.getByTestId('total-stake').first().realHover();
|
||||
it('Should have Staking Guide link visible', function () {
|
||||
// 1002-STKE-003
|
||||
cy.getByTestId(guideLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Read more about staking on Vega')
|
||||
.and(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://docs.vega.xyz/mainnet/concepts/vega-chain/#staking-on-vega'
|
||||
);
|
||||
});
|
||||
|
||||
cy.get(stakedByOperatorToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by operator: 3,000.00');
|
||||
cy.get(stakedByDelegatesToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by delegates: 0.00');
|
||||
cy.get(totalStakedToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Total stake: 3,000.00');
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
cy.getByTestId('normalised-voting-power')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
cy.wrap($vPower).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power tooltip', function () {
|
||||
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||
|
||||
cy.get(unnormalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Unnormalised voting power: 20.00%');
|
||||
cy.get(normalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Normalised voting power: 50.00%');
|
||||
});
|
||||
|
||||
// 2002-SINC-018
|
||||
it('Should be able to see validator total penalties', function () {
|
||||
cy.getByTestId('total-penalty')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($penalties) => {
|
||||
cy.wrap($penalties).should('contain.text', '0%');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator penalties tooltip', function () {
|
||||
cy.getByTestId('total-penalty').realHover();
|
||||
|
||||
cy.get(performancePenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Performance penalty: 0.00%');
|
||||
cy.get(overstakedPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.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 () {
|
||||
cy.getByTestId('total-pending-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($pendingStake) => {
|
||||
cy.wrap($pendingStake).should('contain.text', '0.00');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 2001-STKE-050
|
||||
describe(
|
||||
'Should be able to see static information about a validator',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
before('connect wallets and click on validator', function () {
|
||||
cy.connectVegaWallet();
|
||||
clickOnValidatorFromList(0);
|
||||
});
|
||||
|
||||
// 2001-STKE-006
|
||||
it('Should be able to see validator name', function () {
|
||||
cy.get(validatorTitle).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 2001-STKE-007
|
||||
it('Should be able to see validator id', function () {
|
||||
cy.get(validatorId).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 2001-STKE-008
|
||||
it('Should be able to see validator public key', function () {
|
||||
cy.get(validatorPubKey).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 2001-STKE-010
|
||||
it('Should be able to see Ethereum address', function () {
|
||||
cy.get(ethAddressLink)
|
||||
.should('not.be.empty')
|
||||
.and('have.attr', 'href');
|
||||
});
|
||||
// TODO validators missing url for more information about them 2001-STKE-09
|
||||
|
||||
it('Should be able to see validator status', function () {
|
||||
cy.get(validatorStatus).should('have.text', 'Consensus');
|
||||
});
|
||||
|
||||
// 2001-STKE-012
|
||||
it('Should be able to see total stake', function () {
|
||||
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see pending stake', function () {
|
||||
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by operator', function () {
|
||||
cy.get(stakedByOperator)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by delegates', function () {
|
||||
cy.get(stakedByDelegates)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 2001-STKE-051
|
||||
it('Should be able to see stake share in percentage', function () {
|
||||
cy.get(stakeShare)
|
||||
.invoke('text')
|
||||
.then(($stakePercentage) => {
|
||||
// The pattern must start at a word boundary (\b).
|
||||
// The pattern cannot be immediately preceded by a dot ((?<!\.)).
|
||||
// The pattern can be one of the following:
|
||||
// A percentage value of zero (0%), or
|
||||
// A non-zero percentage value that can be:
|
||||
// A single digit (\d) between 0 and 9, or
|
||||
// A two-digit number between 0 and 99 (\d{1,2}), or
|
||||
// The number 100.
|
||||
// The pattern can optionally include a decimal point and one or more digits after the decimal point ((?:(?<!100)\.\d+)?). However, if the number is 100, it cannot have a decimal point.
|
||||
// The pattern must end with a percentage sign (%).
|
||||
|
||||
cy.wrap($stakePercentage).should(
|
||||
'match',
|
||||
/\b(?<!\.)(?:0+(?:\.0+)?%|(?:\d|\d{1,2}|100)(?:(?<!100)\.\d+)?)%/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// 2001-STKE-011 2002-SINC-001 2002-SINC-002
|
||||
it('Should be able to see epoch information', function () {
|
||||
const epochTitle = 'h3';
|
||||
const nextEpochInfo = 'p';
|
||||
|
||||
cy.get(epochCountDown).within(() => {
|
||||
cy.get(epochTitle).should('not.be.empty');
|
||||
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
// 1002-STKE-032
|
||||
it('Should have button to connect vega wallet in validator page', function () {
|
||||
clickOnValidatorFromList(0);
|
||||
cy.getByTestId('connect-to-vega-wallet-btn').should('be.visible');
|
||||
cy.visit('/validators');
|
||||
});
|
||||
});
|
||||
// 1002-STKE-020 1002-STKE-021 1002-STKE-022 1002-STKE-023 1002-STKE-024
|
||||
describe(
|
||||
'Should be able to see validator list from the staking page',
|
||||
{ tags: '@regression' },
|
||||
function () {
|
||||
// 1002-STKE-050
|
||||
it('Should be able to see validator names', function () {
|
||||
cy.get('[col-id="validator"] > div > span')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($name) => {
|
||||
cy.wrap($name).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake', function () {
|
||||
cy.getByTestId('total-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($stake) => {
|
||||
cy.wrap($stake).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator stake tooltip', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-stake').first().realHover();
|
||||
|
||||
cy.getByTestId(stakedByOperatorToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by operator: 3,000.00');
|
||||
cy.getByTestId(stakedByDelegatesToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Staked by delegates: 0.00');
|
||||
cy.getByTestId(totalStakedToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Total stake: 3,000.00');
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power', function () {
|
||||
cy.getByTestId('normalised-voting-power')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($vPower) => {
|
||||
cy.wrap($vPower).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator normalised voting power tooltip', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('normalised-voting-power').first().realHover();
|
||||
|
||||
cy.getByTestId(unnormalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Unnormalised voting power: 20.00%');
|
||||
cy.getByTestId(normalisedVotingPowerToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Normalised voting power: 50.00%');
|
||||
});
|
||||
|
||||
// 2002-SINC-018
|
||||
it('Should be able to see validator total penalties', function () {
|
||||
cy.getByTestId('total-penalty')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($penalties) => {
|
||||
cy.wrap($penalties).should('contain.text', '0%');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to see validator penalties tooltip', function () {
|
||||
waitForBeginningOfEpoch();
|
||||
cy.getByTestId('total-penalty').realHover();
|
||||
|
||||
cy.getByTestId(performancePenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Performance penalty: 0.00%');
|
||||
cy.getByTestId(overstakedPenaltyToolTip)
|
||||
.invoke('text')
|
||||
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
|
||||
});
|
||||
|
||||
it('Should be able to see validator pending stake', function () {
|
||||
cy.getByTestId('total-pending-stake')
|
||||
.should('have.length.at.least', 1)
|
||||
.each(($pendingStake) => {
|
||||
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%');
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 1002-STKE-050
|
||||
describe(
|
||||
'Should be able to see static information about a validator',
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
before('connect wallets and click on validator', function () {
|
||||
cy.connectVegaWallet();
|
||||
clickOnValidatorFromList(0);
|
||||
});
|
||||
|
||||
// 1002-STKE-006
|
||||
it('Should be able to see validator name', function () {
|
||||
cy.getByTestId(validatorTitle).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-007
|
||||
it('Should be able to see validator id', function () {
|
||||
cy.getByTestId(validatorId).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-008
|
||||
it('Should be able to see validator public key', function () {
|
||||
cy.getByTestId(validatorPubKey).should('not.be.empty');
|
||||
});
|
||||
|
||||
// 1002-STKE-010
|
||||
it('Should be able to see Ethereum address', function () {
|
||||
cy.getByTestId(ethAddressLink)
|
||||
.should('not.be.empty')
|
||||
.and('have.attr', 'href');
|
||||
});
|
||||
// TODO validators missing url for more information about them 1002-STKE-09
|
||||
|
||||
it('Should be able to see validator status', function () {
|
||||
cy.getByTestId(validatorStatus).should('have.text', 'Consensus');
|
||||
});
|
||||
|
||||
// 1002-STKE-012
|
||||
it('Should be able to see total stake', function () {
|
||||
cy.getByTestId(totalStake)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see pending stake', function () {
|
||||
cy.getByTestId(pendingStake)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by operator', function () {
|
||||
cy.getByTestId(stakedByOperator)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
it('Should be able to see staked by delegates', function () {
|
||||
cy.getByTestId(stakedByDelegates)
|
||||
.invoke('text')
|
||||
.should('match', stakeNumberRegex);
|
||||
});
|
||||
|
||||
// 1002-STKE-051
|
||||
it('Should be able to see stake share in percentage', function () {
|
||||
cy.getByTestId(stakeShare)
|
||||
.invoke('text')
|
||||
.then(($stakePercentage) => {
|
||||
// The pattern must start at a word boundary (\b).
|
||||
// The pattern cannot be immediately preceded by a dot ((?<!\.)).
|
||||
// The pattern can be one of the following:
|
||||
// A percentage value of zero (0%), or
|
||||
// A non-zero percentage value that can be:
|
||||
// A single digit (\d) between 0 and 9, or
|
||||
// A two-digit number between 0 and 99 (\d{1,2}), or
|
||||
// The number 100.
|
||||
// The pattern can optionally include a decimal point and one or more digits after the decimal point ((?:(?<!100)\.\d+)?). However, if the number is 100, it cannot have a decimal point.
|
||||
// The pattern must end with a percentage sign (%).
|
||||
|
||||
cy.wrap($stakePercentage).should(
|
||||
'match',
|
||||
/\b(?<!\.)(?:0+(?:\.0+)?%|(?:\d|\d{1,2}|100)(?:(?<!100)\.\d+)?)%/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// 1002-STKE-011 2002-SINC-001 2002-SINC-002
|
||||
it('Should be able to see epoch information', function () {
|
||||
const epochTitle = 'h3';
|
||||
const nextEpochInfo = 'p';
|
||||
|
||||
cy.getByTestId(epochCountDown).within(() => {
|
||||
cy.get(epochTitle).should('not.be.empty');
|
||||
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '../../support/common.functions';
|
||||
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||
|
||||
const connectButton = '[data-testid="connect-to-eth-btn"]';
|
||||
const connectButton = 'connect-to-eth-btn';
|
||||
const lockedTokensInVestingContract = '6,499,972.30';
|
||||
|
||||
context(
|
||||
@@ -29,7 +29,7 @@ context(
|
||||
|
||||
// 1005-VEST-018
|
||||
it('should have connect Eth wallet button', function () {
|
||||
cy.get(connectButton)
|
||||
cy.getByTestId(connectButton)
|
||||
.should('be.visible')
|
||||
.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 connectToEthButton =
|
||||
'[data-testid="connect-to-eth-wallet-button"]:visible';
|
||||
const connectorList = '[data-testid="web3-connector-list"]';
|
||||
const connectorList = 'web3-connector-list';
|
||||
const associate = '[href="/token/associate"]';
|
||||
const disassociate = '[href="/token/disassociate"]';
|
||||
const disconnect = '[data-testid="disconnect-from-eth-wallet-button"]';
|
||||
const accountNo = '[data-testid="ethereum-account-truncated"]';
|
||||
const disconnect = 'disconnect-from-eth-wallet-button';
|
||||
const accountNo = 'ethereum-account-truncated';
|
||||
const currencyTitle = '[data-testid="currency-title"]:visible';
|
||||
const currencyValue = '[data-testid="currency-value"]: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 currencyUnlocked = '[data-testid="currency-unlocked"]:visible';
|
||||
const dialog = '[role="dialog"]:visible';
|
||||
const dialogHeader = '[data-testid="dialog-title"]';
|
||||
const dialogCloseBtn = '[data-testid="dialog-close"]';
|
||||
const dialogHeader = 'dialog-title';
|
||||
const dialogCloseBtn = 'dialog-close';
|
||||
|
||||
context(
|
||||
'Ethereum Wallet - verify elements on widget',
|
||||
@@ -59,7 +59,7 @@ context(
|
||||
|
||||
it('should have Connect Ethereum header visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogHeader)
|
||||
cy.getByTestId(dialogHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect to your Ethereum wallet');
|
||||
});
|
||||
@@ -73,7 +73,7 @@ context(
|
||||
'WalletConnect',
|
||||
'WalletConnect Legacy',
|
||||
];
|
||||
cy.get(connectorList).within(() => {
|
||||
cy.getByTestId(connectorList).within(() => {
|
||||
cy.get('button').each(($btn, i) => {
|
||||
cy.wrap($btn).should('be.visible').and('have.text', connectList[i]);
|
||||
});
|
||||
@@ -83,7 +83,7 @@ context(
|
||||
after('close popup', function () {
|
||||
cy.get(dialog)
|
||||
.within(() => {
|
||||
cy.get(dialogCloseBtn).click();
|
||||
cy.getByTestId(dialogCloseBtn).click();
|
||||
})
|
||||
.should('not.exist');
|
||||
});
|
||||
@@ -106,7 +106,7 @@ context(
|
||||
// 0004-EWAL-005
|
||||
it('should have account number visible', function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(accountNo)
|
||||
cy.getByTestId(accountNo)
|
||||
.should('be.visible')
|
||||
.and('have.text', Cypress.env('ethWalletPublicKeyTruncated'));
|
||||
});
|
||||
@@ -129,7 +129,7 @@ context(
|
||||
// 0004-EWAL-007
|
||||
it('should have Disconnect button visible', function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(disconnect)
|
||||
cy.getByTestId(disconnect)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Disconnect');
|
||||
});
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
import { truncateByChars } from '@vegaprotocol/utils';
|
||||
import { waitForSpinner } from '../../support/common.functions';
|
||||
import { vegaWalletTeardown } from '../../support/wallet-teardown.functions';
|
||||
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||
import {
|
||||
vegaWalletFaucetAssetsWithoutCheck,
|
||||
vegaWalletTeardown,
|
||||
} from '../../support/wallet-functions';
|
||||
|
||||
const walletContainer = 'aside [data-testid="vega-wallet"]';
|
||||
const walletHeader = '[data-testid="wallet-header"] h1';
|
||||
const connectButton = '[data-testid="connect-vega-wallet"]';
|
||||
const getVegaLink = '[data-testid="link"]';
|
||||
const connectButton = 'connect-vega-wallet';
|
||||
const getVegaLink = 'link';
|
||||
const dialog = '[role="dialog"]:visible';
|
||||
const dialogHeader = '[data-testid="dialog-title"]';
|
||||
const walletDialogHeader = '[data-testid="wallet-dialog-title"]';
|
||||
const connectorsList = '[data-testid="connectors-list"]';
|
||||
const dialogCloseBtn = '[data-testid="dialog-close"]';
|
||||
const restConnectorForm = '[data-testid="rest-connector-form"]';
|
||||
const dialogHeader = 'dialog-title';
|
||||
const walletDialogHeader = 'wallet-dialog-title';
|
||||
const connectorsList = 'connectors-list';
|
||||
const dialogCloseBtn = 'dialog-close';
|
||||
const restConnectorForm = 'rest-connector-form';
|
||||
const restWallet = '#wallet';
|
||||
const restPassphrase = '#passphrase';
|
||||
const restConnectBtn = '[type="submit"]';
|
||||
const accountNo = '[data-testid="vega-account-truncated"]';
|
||||
const currencyTitle = '[data-testid="currency-title"]';
|
||||
const currencyValue = '[data-testid="currency-value"]';
|
||||
const accountNo = 'vega-account-truncated';
|
||||
const currencyTitle = 'currency-title';
|
||||
const currencyValue = 'currency-value';
|
||||
const vegaUnstaked = '[data-testid="vega-wallet-balance-unstaked"] .text-right';
|
||||
const governanceBtn = '[href="/proposals"]';
|
||||
const stakingBtn = '[href="/validators"]';
|
||||
const manageLink = '[data-testid="manage-vega-wallet"]';
|
||||
const dialogVegaKey = '[data-testid="vega-public-key-full"]';
|
||||
const dialogDisconnectBtn = '[data-testid="disconnect"]';
|
||||
const copyPublicKeyBtn = '[data-testid="copy-vega-public-key"]';
|
||||
const vegaWalletCurrencyTitle = '[data-testid="currency-title"]';
|
||||
const manageLink = 'manage-vega-wallet';
|
||||
const dialogVegaKey = 'vega-public-key-full';
|
||||
const dialogDisconnectBtn = 'disconnect';
|
||||
const copyPublicKeyBtn = 'copy-vega-public-key';
|
||||
const vegaWalletCurrencyTitle = 'currency-title';
|
||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||
const txTimeout = Cypress.env('txTimeout');
|
||||
|
||||
@@ -45,10 +47,10 @@ context(
|
||||
cy.get(walletHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Vega Wallet');
|
||||
cy.get(connectButton)
|
||||
cy.getByTestId(connectButton)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet to use associated $VEGA');
|
||||
cy.get(getVegaLink)
|
||||
cy.getByTestId(getVegaLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Get a Vega wallet')
|
||||
.and('have.attr', 'href', 'https://vega.xyz/wallet');
|
||||
@@ -59,20 +61,20 @@ context(
|
||||
describe('when connect button clicked', () => {
|
||||
before('click connect vega wallet button', () => {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(connectButton).click();
|
||||
cy.getByTestId(connectButton).click();
|
||||
});
|
||||
});
|
||||
|
||||
it('should have Connect Vega header visible', () => {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(walletDialogHeader)
|
||||
cy.getByTestId(walletDialogHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have jsonRpc and hosted connection options visible on list', function () {
|
||||
cy.get(connectorsList).within(() => {
|
||||
cy.getByTestId(connectorsList).within(() => {
|
||||
cy.getByTestId('connector-jsonRpc')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
@@ -84,33 +86,33 @@ context(
|
||||
|
||||
it('should have close button visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogCloseBtn).should('be.visible');
|
||||
cy.getByTestId(dialogCloseBtn).should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rest connector form opened', function () {
|
||||
before('click hosted wallet app button', function () {
|
||||
cy.get(connectorsList).within(() => {
|
||||
cy.getByTestId(connectorsList).within(() => {
|
||||
cy.getByTestId('connector-hosted').click();
|
||||
});
|
||||
});
|
||||
|
||||
// 0002-WCON-002
|
||||
it('should have wallet field visible', function () {
|
||||
cy.get(restConnectorForm).within(() => {
|
||||
cy.getByTestId(restConnectorForm).within(() => {
|
||||
cy.get(restWallet).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have password field visible', function () {
|
||||
cy.get(restConnectorForm).within(() => {
|
||||
cy.getByTestId(restConnectorForm).within(() => {
|
||||
cy.get(restPassphrase).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have connect button visible', function () {
|
||||
cy.get(restConnectorForm).within(() => {
|
||||
cy.getByTestId(restConnectorForm).within(() => {
|
||||
cy.get(restConnectBtn)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect');
|
||||
@@ -119,12 +121,12 @@ context(
|
||||
|
||||
it('should have close button visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogCloseBtn).should('be.visible');
|
||||
cy.getByTestId(dialogCloseBtn).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
after('close dialog', function () {
|
||||
cy.get(dialogCloseBtn).click().should('not.exist');
|
||||
cy.getByTestId(dialogCloseBtn).click().should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -150,7 +152,7 @@ context(
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(accountNo)
|
||||
cy.getByTestId(accountNo)
|
||||
.should('be.visible')
|
||||
.and('have.text', Cypress.env('vegaWalletPublicKeyShort'));
|
||||
});
|
||||
@@ -159,7 +161,7 @@ context(
|
||||
|
||||
it('should have Vega Associated currency title visible', function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(currencyTitle)
|
||||
cy.getByTestId(currencyTitle)
|
||||
.should('be.visible')
|
||||
.and('contain.text', `VEGAAssociated`);
|
||||
});
|
||||
@@ -170,7 +172,7 @@ context(
|
||||
{ tags: '@smoke' },
|
||||
function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(currencyValue)
|
||||
cy.getByTestId(currencyValue)
|
||||
.should('be.visible')
|
||||
.and('contain.text', `0.00`);
|
||||
});
|
||||
@@ -202,21 +204,23 @@ context(
|
||||
|
||||
it('should have Manage link visible', function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(manageLink).should('be.visible').and('have.text', 'Manage');
|
||||
cy.getByTestId(manageLink)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Manage');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when Manage dialog opened', function () {
|
||||
before('click Manage link', function () {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(manageLink).click();
|
||||
cy.getByTestId(manageLink).click();
|
||||
});
|
||||
});
|
||||
|
||||
// 0002-WCON-025, 0002-WCON-026
|
||||
it('should have SELECT A VEGA KEY dialog title visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogHeader)
|
||||
cy.getByTestId(dialogHeader)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'SELECT A VEGA KEY');
|
||||
});
|
||||
@@ -236,7 +240,7 @@ context(
|
||||
'contain.text',
|
||||
truncatedPubKey1
|
||||
);
|
||||
cy.get(dialogVegaKey)
|
||||
cy.getByTestId(dialogVegaKey)
|
||||
.should('be.visible')
|
||||
.and('contain.text', truncatedPubKey1)
|
||||
.and('contain.text', truncatedPubKey2);
|
||||
@@ -246,7 +250,7 @@ context(
|
||||
// 0002-WCON-029
|
||||
it('should have copy public key button visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(copyPublicKeyBtn)
|
||||
cy.getByTestId(copyPublicKeyBtn)
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'Copy');
|
||||
});
|
||||
@@ -254,13 +258,13 @@ context(
|
||||
|
||||
it('should have close button visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogCloseBtn).should('be.visible');
|
||||
cy.getByTestId(dialogCloseBtn).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have vega Disconnect all keys button visible', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogDisconnectBtn)
|
||||
cy.getByTestId(dialogDisconnectBtn)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Disconnect all keys');
|
||||
});
|
||||
@@ -269,10 +273,10 @@ context(
|
||||
// 0002-WCON-022
|
||||
it('should be able to disconnect all keys', function () {
|
||||
cy.get(dialog).within(() => {
|
||||
cy.get(dialogDisconnectBtn).click();
|
||||
cy.getByTestId(dialogDisconnectBtn).click();
|
||||
});
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(connectButton).should('be.visible'); // 0002-WCON-023
|
||||
cy.getByTestId(connectButton).should('be.visible'); // 0002-WCON-023
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -285,28 +289,28 @@ context(
|
||||
name: 'USDC (fake)',
|
||||
symbol: 'fUSDC',
|
||||
amount: '1000000',
|
||||
expectedAmount: '10.00',
|
||||
expectedAmount: 10.0,
|
||||
},
|
||||
{
|
||||
id: '8566db7257222b5b7ef2886394ad28b938b28680a54a169bbc795027b89d6665',
|
||||
name: 'DAI (fake)',
|
||||
symbol: 'fDAI',
|
||||
amount: '200000',
|
||||
expectedAmount: '2.00',
|
||||
expectedAmount: 2.0,
|
||||
},
|
||||
{
|
||||
id: '73174a6fb1d5802ba0ac7bd7ab79e0a3a4837b262de0a4e80815a55442692bd0',
|
||||
name: 'BTC (fake)',
|
||||
symbol: 'fBTC',
|
||||
amount: '600000',
|
||||
expectedAmount: '6.00',
|
||||
expectedAmount: 6.0,
|
||||
},
|
||||
{
|
||||
id: 'e02d4c15d790d1d2dffaf2dcd1cf06a1fe656656cf4ed18c8ce99f9e83643567',
|
||||
name: 'EURO (fake)',
|
||||
symbol: 'fEURO',
|
||||
amount: '800000',
|
||||
expectedAmount: '8.00',
|
||||
expectedAmount: 8.0,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -328,19 +332,20 @@ context(
|
||||
for (const { name, symbol, expectedAmount } of assets) {
|
||||
it(`should see ${name} within vega wallet`, () => {
|
||||
cy.get(walletContainer).within(() => {
|
||||
cy.get(vegaWalletCurrencyTitle)
|
||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||
.contains(name, txTimeout)
|
||||
.should('be.visible');
|
||||
|
||||
cy.get(vegaWalletCurrencyTitle)
|
||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||
.contains(name)
|
||||
.parent()
|
||||
.siblings()
|
||||
.invoke('text')
|
||||
.then(parseFloat)
|
||||
.should('be.gte', parseFloat(expectedAmount));
|
||||
.then((elementAmount) => {
|
||||
const displayedAmount = parseFloat(elementAmount.text());
|
||||
expect(displayedAmount).be.gte(expectedAmount);
|
||||
});
|
||||
|
||||
cy.get(vegaWalletCurrencyTitle)
|
||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||
.contains(name)
|
||||
.parent()
|
||||
.contains(symbol);
|
||||
|
||||
@@ -5,8 +5,6 @@ import {
|
||||
verifyTabHighlighted,
|
||||
} from '../../support/common.functions';
|
||||
|
||||
const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||
|
||||
context(
|
||||
'Withdraw Page - verify elements on page',
|
||||
{ tags: '@smoke' },
|
||||
@@ -26,7 +24,7 @@ context(
|
||||
});
|
||||
|
||||
it('should have connect Vega wallet button', function () {
|
||||
cy.get(connectToVegaBtn)
|
||||
cy.getByTestId('connect-to-vega-wallet-btn')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Connect Vega wallet');
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ export function navigateTo(page: navigation) {
|
||||
});
|
||||
} else {
|
||||
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
||||
cy.get(page).eq(0).click();
|
||||
cy.get(page).eq(0).click({ force: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import './common.functions.ts';
|
||||
import './staking.functions.ts';
|
||||
import './governance.functions.ts';
|
||||
import './wallet-eth.functions.ts';
|
||||
import './wallet-teardown.functions.ts';
|
||||
import './wallet-vega.functions.ts';
|
||||
import './wallet-functions.ts';
|
||||
import './proposal.functions.ts';
|
||||
import 'cypress-mochawesome-reporter/register';
|
||||
import registerCypressGrep from '@cypress/grep';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { closeDialog } from './common.functions';
|
||||
import { vegaWalletTeardown } from './wallet-teardown.functions';
|
||||
import { vegaWalletTeardown } from './wallet-functions';
|
||||
|
||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||
|
||||
+27
@@ -139,6 +139,9 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
||||
$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);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -173,3 +176,27 @@ export async function vegaWalletDisassociate(amount: string) {
|
||||
amount = amount + '0'.repeat(18);
|
||||
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
||||
}
|
||||
|
||||
export function vegaWalletFaucetAssetsWithoutCheck(
|
||||
asset: string,
|
||||
amount: string,
|
||||
vegaWalletPublicKey: string
|
||||
) {
|
||||
cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`);
|
||||
cy.exec(
|
||||
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint`
|
||||
)
|
||||
.its('stdout')
|
||||
.then((response) => {
|
||||
assert.include(
|
||||
response,
|
||||
`"success":true`,
|
||||
'Ensuring curl command was successfully undertaken'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function switchVegaWalletPubKey() {
|
||||
cy.get('[data-testid="manage-vega-wallet"]:visible').click();
|
||||
cy.get('[data-testid="select-keypair-button"]').eq(0).click();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
export function vegaWalletFaucetAssetsWithoutCheck(
|
||||
asset: string,
|
||||
amount: string,
|
||||
vegaWalletPublicKey: string
|
||||
) {
|
||||
cy.highlight(`Topping up vega wallet with ${asset}, amount: ${amount}`);
|
||||
cy.exec(
|
||||
`curl -X POST -d '{"amount": "${amount}", "asset": "${asset}", "party": "${vegaWalletPublicKey}"}' http://localhost:1790/api/v1/mint`
|
||||
)
|
||||
.its('stdout')
|
||||
.then((response) => {
|
||||
assert.include(
|
||||
response,
|
||||
`"success":true`,
|
||||
'Ensuring curl command was successfully undertaken'
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { CollapsibleToggle } from './collapsible-toggle';
|
||||
|
||||
describe('CollapsibleToggle', () => {
|
||||
const testId = 'collapsible-toggle';
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const mockSetToggleState = jest.fn();
|
||||
const { getByTestId, getByText } = render(
|
||||
<CollapsibleToggle
|
||||
toggleState={false}
|
||||
setToggleState={mockSetToggleState}
|
||||
dataTestId={testId}
|
||||
>
|
||||
<div>Test</div>
|
||||
</CollapsibleToggle>
|
||||
);
|
||||
|
||||
expect(getByTestId(testId)).toBeInTheDocument();
|
||||
expect(getByText('Test')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls setToggleState with the opposite of current toggleState when clicked', () => {
|
||||
const mockSetToggleState = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<CollapsibleToggle
|
||||
toggleState={false}
|
||||
setToggleState={mockSetToggleState}
|
||||
dataTestId={testId}
|
||||
>
|
||||
<div>Test</div>
|
||||
</CollapsibleToggle>
|
||||
);
|
||||
|
||||
fireEvent.click(getByTestId(testId));
|
||||
|
||||
expect(mockSetToggleState).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('has the rotate-180 class if toggleState is true', () => {
|
||||
const mockSetToggleState = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<CollapsibleToggle
|
||||
toggleState={true}
|
||||
setToggleState={mockSetToggleState}
|
||||
dataTestId={testId}
|
||||
>
|
||||
<div>Test</div>
|
||||
</CollapsibleToggle>
|
||||
);
|
||||
|
||||
expect(getByTestId('toggle-icon-wrapper')).toHaveClass('rotate-180');
|
||||
});
|
||||
|
||||
it('does not have the rotate-180 class if toggleState is false', () => {
|
||||
const mockSetToggleState = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<CollapsibleToggle
|
||||
toggleState={false}
|
||||
setToggleState={mockSetToggleState}
|
||||
dataTestId={testId}
|
||||
>
|
||||
<div>Test</div>
|
||||
</CollapsibleToggle>
|
||||
);
|
||||
|
||||
expect(getByTestId('toggle-icon-wrapper')).not.toHaveClass('rotate-180');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import classnames from 'classnames';
|
||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import type { Dispatch, SetStateAction, ReactNode } from 'react';
|
||||
|
||||
interface CollapsibleToggleProps {
|
||||
toggleState: boolean;
|
||||
setToggleState: Dispatch<SetStateAction<boolean>>;
|
||||
children: ReactNode;
|
||||
dataTestId?: string;
|
||||
}
|
||||
|
||||
export const CollapsibleToggle = ({
|
||||
toggleState,
|
||||
setToggleState,
|
||||
dataTestId,
|
||||
children,
|
||||
}: CollapsibleToggleProps) => {
|
||||
const classes = classnames(
|
||||
'mb-4 transition-transform ease-in-out duration-300',
|
||||
{
|
||||
'rotate-180': toggleState,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => setToggleState(!toggleState)}
|
||||
data-testid={dataTestId}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
{children}
|
||||
<div className={classes} data-testid="toggle-icon-wrapper">
|
||||
<Icon name="chevron-down" size={8} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './collapsible-toggle';
|
||||
@@ -596,6 +596,8 @@
|
||||
"noPercentage": "No percentage",
|
||||
"proposalJson": "Full proposal JSON",
|
||||
"proposalDetails": "Proposal details",
|
||||
"marketSpecification": "Market specification",
|
||||
"viewMarketJson": "View market JSON",
|
||||
"proposalDescription": "Description",
|
||||
"currentlySetTo": "Currently expected to ",
|
||||
"currently": "currently",
|
||||
@@ -729,7 +731,11 @@
|
||||
"ThisWillSetValidationDeadlineTo": "This will set the validation deadline to",
|
||||
"Hours": "hours",
|
||||
"ThisWillAdd2MinutesToAllowTimeToConfirmInWallet": "Note: 2 minutes of extra time are added when you choose the minimum value. This gives you time to confirm the proposal in your wallet.",
|
||||
"ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "Proposal will fail if enactment is earlier than the voting deadline",
|
||||
"ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline": "The proposal will fail if enactment is earlier than the voting deadline",
|
||||
"ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline": "The proposal will fail if enactment deadline is below the minimum",
|
||||
"ProposalWillFailIfVotingIsBelowTheMinimumDeadline": "The proposal will fail if voting deadline is below the minimum",
|
||||
"ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline": "The proposal will fail if enactment deadline is above the maximum",
|
||||
"ProposalWillFailIfVotingIsAboveTheMaximumDeadline": "The proposal will fail if voting deadline is above the maximum",
|
||||
"SelectAMarketToChange": "Select a market to change",
|
||||
"MarketName": "Market name",
|
||||
"MarketCode": "Market code",
|
||||
@@ -780,6 +786,7 @@
|
||||
"performancePenalty": "Performance penalty",
|
||||
"overstaked": "Overstaked",
|
||||
"overstakedPenalty": "Overstaked penalty",
|
||||
"multisigPenalty": "Multisig penalty",
|
||||
"homeProposalsIntro": "Decisions on the Vega network are on-chain, with tokenholders creating proposals that other tokenholders vote to approve or reject. Network upgrades are proposed and approved by validators.",
|
||||
"homeProposalsButtonText": "Browse, vote, and propose",
|
||||
"homeValidatorsIntro": "Vega runs on a delegated proof of stake blockchain, where validators earn fees for validating block transactions. Tokenholders can nominate validators by staking tokens to them.",
|
||||
@@ -824,5 +831,10 @@
|
||||
"disclaimer5": "No developer of the Vega Governance App accepts any responsibility for, or liability to users in connection with their use of the Vega Governance App.",
|
||||
"multisigContractLink": "Ethereum Multisig Contract",
|
||||
"multisigContractIncorrect": "is incorrectly configured. Validator and delegator rewards will be penalised until this is resolved.",
|
||||
"learnMore": "Learn more"
|
||||
"learnMore": "Learn more",
|
||||
"AllValidators": "All validators",
|
||||
"AllProposals": "All proposals",
|
||||
"RejectedProposals": "Rejected proposals",
|
||||
"networkGovernance": "Network governance",
|
||||
"networkUpgrades": "Network upgrades"
|
||||
}
|
||||
|
||||
+8
-15
@@ -1,9 +1,9 @@
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import classnames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
|
||||
export const ProposalDescription = ({
|
||||
description,
|
||||
@@ -12,23 +12,16 @@ export const ProposalDescription = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [showDescription, setShowDescription] = useState(false);
|
||||
const showDescriptionIconClasses = classnames('mb-4', {
|
||||
'rotate-180': showDescription,
|
||||
});
|
||||
|
||||
return (
|
||||
<section data-testid="proposal-description">
|
||||
<button
|
||||
onClick={() => setShowDescription(!showDescription)}
|
||||
data-testid="proposal-description-toggle"
|
||||
<CollapsibleToggle
|
||||
toggleState={showDescription}
|
||||
setToggleState={setShowDescription}
|
||||
dataTestId={'proposal-description-toggle'}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<SubHeading title={t('proposalDescription')} />
|
||||
<div className={showDescriptionIconClasses}>
|
||||
<Icon name="chevron-down" size={8} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<SubHeading title={t('proposalDescription')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDescription && (
|
||||
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import classnames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
|
||||
@@ -13,23 +13,16 @@ export const ProposalJson = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
const showDetailsIconClasses = classnames('mb-4', {
|
||||
'rotate-180': showDetails,
|
||||
});
|
||||
|
||||
return (
|
||||
<section data-testid="proposal-json">
|
||||
<button
|
||||
onClick={() => setShowDetails(!showDetails)}
|
||||
data-testid="proposal-json-toggle"
|
||||
<CollapsibleToggle
|
||||
toggleState={showDetails}
|
||||
setToggleState={setShowDetails}
|
||||
dataTestId="proposal-json-toggle"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<SubHeading title={t('proposalJson')} />
|
||||
<div className={showDetailsIconClasses}>
|
||||
<Icon name="chevron-down" size={8} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<SubHeading title={t('proposalJson')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDetails && <SyntaxHighlighter data={proposal} />}
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './proposal-market-data';
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
InstrumentInfoPanel,
|
||||
KeyDetailsInfoPanel,
|
||||
LiquidityMonitoringParametersInfoPanel,
|
||||
LiquidityPriceRangeInfoPanel,
|
||||
MetadataInfoPanel,
|
||||
OracleInfoPanel,
|
||||
PriceMonitoringBoundsInfoPanel,
|
||||
RiskFactorsInfoPanel,
|
||||
RiskModelInfoPanel,
|
||||
RiskParametersInfoPanel,
|
||||
SettlementAssetInfoPanel,
|
||||
} from '@vegaprotocol/markets';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
Button,
|
||||
CopyWithTooltip,
|
||||
Dialog,
|
||||
Icon,
|
||||
SyntaxHighlighter,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||
import type { DataSourceDefinition } from '@vegaprotocol/types';
|
||||
import { create } from 'zustand';
|
||||
|
||||
type MarketDataDialogState = {
|
||||
isOpen: boolean;
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
export const useMarketDataDialogStore = create<MarketDataDialogState>(
|
||||
(set) => ({
|
||||
isOpen: false,
|
||||
open: () => set({ isOpen: true }),
|
||||
close: () => set({ isOpen: false }),
|
||||
})
|
||||
);
|
||||
|
||||
export const ProposalMarketData = ({
|
||||
marketData,
|
||||
}: {
|
||||
marketData: MarketInfoWithData;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, open, close } = useMarketDataDialogStore();
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
|
||||
if (!marketData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const settlementData = marketData.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForSettlementData.data as DataSourceDefinition;
|
||||
const terminationData = marketData.tradableInstrument.instrument.product
|
||||
.dataSourceSpecForTradingTermination.data as DataSourceDefinition;
|
||||
|
||||
const getSigners = (data: DataSourceDefinition) => {
|
||||
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
|
||||
const signers = data.sourceType.sourceType.signers || [];
|
||||
|
||||
return signers.map(({ signer }) => {
|
||||
return (
|
||||
(signer.__typename === 'ETHAddress' && signer.address) ||
|
||||
(signer.__typename === 'PubKey' && signer.key)
|
||||
);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="relative" data-testid="proposal-market-data">
|
||||
<CollapsibleToggle
|
||||
toggleState={showDetails}
|
||||
setToggleState={setShowDetails}
|
||||
dataTestId="proposal-market-data-toggle"
|
||||
>
|
||||
<SubHeading title={t('marketSpecification')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDetails && (
|
||||
<>
|
||||
<div className="float-right">
|
||||
<Button onClick={open} data-testid="view-market-json">
|
||||
{t('viewMarketJson')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mb-10">
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
itemId="key-details"
|
||||
title={t('Key details')}
|
||||
content={<KeyDetailsInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="instrument"
|
||||
title={t('Instrument')}
|
||||
content={<InstrumentInfoPanel market={marketData} />}
|
||||
/>
|
||||
{isEqual(
|
||||
getSigners(settlementData),
|
||||
getSigners(terminationData)
|
||||
) ? (
|
||||
<AccordionItem
|
||||
itemId="oracles"
|
||||
title={t('Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<AccordionItem
|
||||
itemId="settlement-oracle"
|
||||
title={t('Settlement Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel
|
||||
market={marketData}
|
||||
type="settlementData"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<AccordionItem
|
||||
itemId="termination-oracle"
|
||||
title={t('Termination Oracle')}
|
||||
content={
|
||||
<OracleInfoPanel market={marketData} type="termination" />
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<AccordionItem
|
||||
itemId="settlement-asset"
|
||||
title={t('Settlement asset')}
|
||||
content={<SettlementAssetInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="metadata"
|
||||
title={t('Metadata')}
|
||||
content={<MetadataInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-model"
|
||||
title={t('Risk model')}
|
||||
content={<RiskModelInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-parameters"
|
||||
title={t('Risk parameters')}
|
||||
content={<RiskParametersInfoPanel market={marketData} />}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="risk-factors"
|
||||
title={t('Risk factors')}
|
||||
content={<RiskFactorsInfoPanel market={marketData} />}
|
||||
/>
|
||||
{(
|
||||
marketData.priceMonitoringSettings?.parameters?.triggers || []
|
||||
).map((_, triggerIndex) => (
|
||||
<AccordionItem
|
||||
itemId={`trigger-${triggerIndex}`}
|
||||
title={t(`Price monitoring bounds ${triggerIndex + 1}`)}
|
||||
content={
|
||||
<PriceMonitoringBoundsInfoPanel
|
||||
market={marketData}
|
||||
triggerIndex={triggerIndex}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<AccordionItem
|
||||
itemId="liqudity-monitoring-parameters"
|
||||
title={t('Liquidity monitoring parameters')}
|
||||
content={
|
||||
<LiquidityMonitoringParametersInfoPanel market={marketData} />
|
||||
}
|
||||
/>
|
||||
<AccordionItem
|
||||
itemId="liquidity-price-range"
|
||||
title={t('Liquidity price range')}
|
||||
content={<LiquidityPriceRangeInfoPanel market={marketData} />}
|
||||
/>
|
||||
</Accordion>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Dialog
|
||||
title={marketData.tradableInstrument.instrument.code}
|
||||
open={isOpen}
|
||||
onChange={(isOpen) => (isOpen ? open() : close())}
|
||||
size="medium"
|
||||
dataTestId="market-json-dialog"
|
||||
>
|
||||
<CopyWithTooltip text={JSON.stringify(marketData)}>
|
||||
<button className="bg-vega-dark-100 rounded-sm py-2 px-3 mb-4 text-white">
|
||||
<span>
|
||||
<Icon name="duplicate" />
|
||||
</span>
|
||||
<span className="ml-2">Copy</span>
|
||||
</button>
|
||||
</CopyWithTooltip>
|
||||
<SyntaxHighlighter data={marketData} />
|
||||
</Dialog>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
+7
-16
@@ -1,4 +1,3 @@
|
||||
import classnames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@@ -6,13 +5,13 @@ import {
|
||||
KeyValueTableRow,
|
||||
Thumbs,
|
||||
RoundedWrapper,
|
||||
Icon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { formatNumber, formatNumberPercentage } from '@vegaprotocol/utils';
|
||||
import { SubHeading } from '../../../../components/heading';
|
||||
import { useVoteInformation } from '../../hooks';
|
||||
import { useAppState } from '../../../../contexts/app-state/app-state-context';
|
||||
import { ProposalType } from '../proposal/proposal';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
|
||||
@@ -57,23 +56,15 @@ export const ProposalVotesTable = ({
|
||||
? t('byTokenVote')
|
||||
: t('byLiquidityVote');
|
||||
|
||||
const showDetailsIconClasses = classnames('mb-4', {
|
||||
'rotate-180': showDetails,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setShowDetails(!showDetails)}
|
||||
data-testid="vote-breakdown-toggle"
|
||||
<CollapsibleToggle
|
||||
toggleState={showDetails}
|
||||
setToggleState={setShowDetails}
|
||||
dataTestId="vote-breakdown-toggle"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<SubHeading title={t('voteBreakdown')} />
|
||||
<div className={showDetailsIconClasses}>
|
||||
<Icon name="chevron-down" size={8} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<SubHeading title={t('voteBreakdown')} />
|
||||
</CollapsibleToggle>
|
||||
|
||||
{showDetails && (
|
||||
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||
import { Proposal } from './proposal';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
|
||||
jest.mock('@vegaprotocol/network-parameters', () => ({
|
||||
...jest.requireActual('@vegaprotocol/network-parameters'),
|
||||
@@ -28,9 +30,6 @@ jest.mock('../proposal-change-table', () => ({
|
||||
jest.mock('../proposal-json', () => ({
|
||||
ProposalJson: () => <div data-testid="proposal-json"></div>,
|
||||
}));
|
||||
jest.mock('../proposal-terms/proposal-terms', () => ({
|
||||
ProposalTerms: () => <div data-testid="proposal-terms"></div>,
|
||||
}));
|
||||
jest.mock('../proposal-votes-table', () => ({
|
||||
ProposalVotesTable: () => <div data-testid="proposal-votes-table"></div>,
|
||||
}));
|
||||
@@ -41,23 +40,49 @@ jest.mock('../list-asset', () => ({
|
||||
ListAsset: () => <div data-testid="proposal-list-asset"></div>,
|
||||
}));
|
||||
|
||||
const renderComponent = (proposal: ProposalQuery['proposal']) => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<Proposal
|
||||
restData={{}}
|
||||
proposal={proposal as ProposalQuery['proposal']}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
it('Renders with data-testid', async () => {
|
||||
const proposal = generateProposal();
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
renderComponent(proposal);
|
||||
|
||||
expect(await screen.findByTestId('proposal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders with a link back to "all proposals"', async () => {
|
||||
const proposal = generateProposal();
|
||||
renderComponent(proposal);
|
||||
|
||||
expect(await screen.findByTestId('all-proposals-link')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders a rejected proposals with a link back to "rejected proposals"', async () => {
|
||||
const proposal = generateProposal({
|
||||
state: ProposalState.STATE_REJECTED,
|
||||
});
|
||||
renderComponent(proposal);
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('rejected-proposals-link')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders each section', async () => {
|
||||
const proposal = generateProposal();
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
renderComponent(proposal);
|
||||
|
||||
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-json')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-terms')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('proposal-vote-details')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('proposal-list-asset')).not.toBeInTheDocument();
|
||||
@@ -80,8 +105,7 @@ it('renders whitelist section if proposal is new asset and source is erc20', asy
|
||||
},
|
||||
},
|
||||
});
|
||||
render(
|
||||
<Proposal restData={{}} proposal={proposal as ProposalQuery['proposal']} />
|
||||
);
|
||||
renderComponent(proposal);
|
||||
|
||||
expect(screen.getByTestId('proposal-list-asset')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
import { AsyncRenderer, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { AsyncRenderer, Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
|
||||
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import { ProposalDescription } from '../proposal-description';
|
||||
import { ProposalChangeTable } from '../proposal-change-table';
|
||||
import { ProposalJson } from '../proposal-json';
|
||||
import { ProposalTerms } from '../proposal-terms';
|
||||
import { ProposalVotesTable } from '../proposal-votes-table';
|
||||
import { VoteDetails } from '../vote-details';
|
||||
import { ListAsset } from '../list-asset';
|
||||
import Routes from '../../../routes';
|
||||
import { ProposalMarketData } from '../proposal-market-data';
|
||||
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/markets';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
|
||||
export enum ProposalType {
|
||||
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
|
||||
@@ -24,11 +29,17 @@ export enum ProposalType {
|
||||
}
|
||||
export interface ProposalProps {
|
||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||
newMarketData?: MarketInfoWithData | null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
restData: any;
|
||||
}
|
||||
|
||||
export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
||||
export const Proposal = ({
|
||||
proposal,
|
||||
restData,
|
||||
newMarketData,
|
||||
}: ProposalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { params, loading, error } = useNetworkParams([
|
||||
NetworkParams.governance_proposal_market_minVoterBalance,
|
||||
NetworkParams.governance_proposal_updateMarket_minVoterBalance,
|
||||
@@ -81,52 +92,77 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
|
||||
return (
|
||||
<AsyncRenderer data={params} loading={loading} error={error}>
|
||||
<section data-testid="proposal">
|
||||
<div className="flex items-center gap-1">
|
||||
<Icon name={'chevron-left'} />
|
||||
|
||||
{proposal.state === ProposalState.STATE_REJECTED ? (
|
||||
<div data-testid="rejected-proposals-link">
|
||||
<Link className="underline" to={Routes.PROPOSALS_REJECTED}>
|
||||
{t('RejectedProposals')}
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<div data-testid="all-proposals-link">
|
||||
<Link className="underline" to={Routes.PROPOSALS}>
|
||||
{t('AllProposals')}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProposalHeader proposal={proposal} isListItem={false} />
|
||||
|
||||
<div className="my-10">
|
||||
<ProposalChangeTable proposal={proposal} />
|
||||
</div>
|
||||
<div id="details">
|
||||
<div className="my-10">
|
||||
<ProposalChangeTable proposal={proposal} />
|
||||
</div>
|
||||
|
||||
{proposal.terms.change.__typename === 'NewAsset' &&
|
||||
proposal.terms.change.source.__typename === 'ERC20' &&
|
||||
proposal.id ? (
|
||||
<ListAsset
|
||||
assetId={proposal.id}
|
||||
withdrawalThreshold={proposal.terms.change.source.withdrawThreshold}
|
||||
lifetimeLimit={proposal.terms.change.source.lifetimeLimit}
|
||||
/>
|
||||
) : null}
|
||||
{proposal.terms.change.__typename === 'NewAsset' &&
|
||||
proposal.terms.change.source.__typename === 'ERC20' &&
|
||||
proposal.id ? (
|
||||
<ListAsset
|
||||
assetId={proposal.id}
|
||||
withdrawalThreshold={
|
||||
proposal.terms.change.source.withdrawThreshold
|
||||
}
|
||||
lifetimeLimit={proposal.terms.change.source.lifetimeLimit}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<div className="mb-4">
|
||||
<ProposalDescription description={proposal.rationale.description} />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<ProposalDescription description={proposal.rationale.description} />
|
||||
</div>
|
||||
|
||||
{proposal.terms.change.__typename !== 'NewMarket' &&
|
||||
proposal.terms.change.__typename !== 'UpdateMarket' && (
|
||||
{newMarketData && (
|
||||
<div className="mb-4">
|
||||
<ProposalTerms data={proposal.terms} />
|
||||
<ProposalMarketData marketData={newMarketData} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-6">
|
||||
<ProposalJson proposal={restData?.data?.proposal} />
|
||||
<div className="mb-6">
|
||||
<ProposalJson proposal={restData?.data?.proposal} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-10">
|
||||
<RoundedWrapper paddingBottom={true}>
|
||||
<VoteDetails
|
||||
<div id="voting">
|
||||
<div className="mb-10">
|
||||
<RoundedWrapper paddingBottom={true}>
|
||||
<VoteDetails
|
||||
proposal={proposal}
|
||||
proposalType={proposalType}
|
||||
minVoterBalance={minVoterBalance}
|
||||
spamProtectionMinTokens={
|
||||
params?.spam_protection_voting_min_tokens
|
||||
}
|
||||
/>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<ProposalVotesTable
|
||||
proposal={proposal}
|
||||
proposalType={proposalType}
|
||||
minVoterBalance={minVoterBalance}
|
||||
spamProtectionMinTokens={
|
||||
params?.spam_protection_voting_min_tokens
|
||||
}
|
||||
/>
|
||||
</RoundedWrapper>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<ProposalVotesTable proposal={proposal} proposalType={proposalType} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</AsyncRenderer>
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import { ProposalsListFilter } from './proposals-list-filter';
|
||||
|
||||
describe('ProposalsListFilter', () => {
|
||||
let setFilterString: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
setFilterString = jest.fn();
|
||||
render(
|
||||
<ProposalsListFilter filterString="" setFilterString={setFilterString} />
|
||||
);
|
||||
});
|
||||
|
||||
it('renders successfully', () => {
|
||||
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle the filter toggle click', () => {
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle input change', () => {
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'test' },
|
||||
});
|
||||
|
||||
expect(setFilterString).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
// 'clear filter' tests are handled in the proposals-list.spec.tsx file
|
||||
// as it is responsible for the filter state
|
||||
});
|
||||
+25
-10
@@ -1,13 +1,16 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useState } from 'react';
|
||||
import { ButtonLink, FormGroup, Input } from '@vegaprotocol/ui-toolkit';
|
||||
import { FormGroup, Icon, Input } from '@vegaprotocol/ui-toolkit';
|
||||
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
interface ProposalsListFilterProps {
|
||||
filterString: string;
|
||||
setFilterString: Dispatch<SetStateAction<string>>;
|
||||
}
|
||||
|
||||
export const ProposalsListFilter = ({
|
||||
filterString,
|
||||
setFilterString,
|
||||
}: ProposalsListFilterProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -15,27 +18,39 @@ export const ProposalsListFilter = ({
|
||||
|
||||
return (
|
||||
<div data-testid="proposals-list-filter" className="mb-4">
|
||||
{!filterVisible && (
|
||||
<ButtonLink
|
||||
onClick={() => setFilterVisible(true)}
|
||||
data-testid="set-proposals-filter-visible"
|
||||
>
|
||||
{t('FilterProposals')}
|
||||
</ButtonLink>
|
||||
)}
|
||||
<CollapsibleToggle
|
||||
toggleState={filterVisible}
|
||||
setToggleState={setFilterVisible}
|
||||
dataTestId={'proposal-filter-toggle'}
|
||||
>
|
||||
<div className="text-xl mb-4">{t('FilterProposals')}</div>
|
||||
</CollapsibleToggle>
|
||||
|
||||
{filterVisible && (
|
||||
<div data-testid="open-proposals-list-filter">
|
||||
<div data-testid="proposals-list-filter-visible">
|
||||
<p>{t('FilterProposalsDescription')}</p>
|
||||
<FormGroup
|
||||
label="Filter text input"
|
||||
labelFor="filter-input"
|
||||
hideLabel={true}
|
||||
className="relative"
|
||||
>
|
||||
<Input
|
||||
value={filterString}
|
||||
data-testid="filter-input"
|
||||
id="filter-input"
|
||||
onChange={(e) => setFilterString(e.target.value)}
|
||||
className="pr-8"
|
||||
/>
|
||||
{filterString && filterString.length > 0 && (
|
||||
<button
|
||||
className="absolute top-2 right-2"
|
||||
onClick={() => setFilterString('')}
|
||||
data-testid="clear-filter"
|
||||
>
|
||||
<Icon name="cross" size={6} className="text-vega-light-200" />
|
||||
</button>
|
||||
)}
|
||||
</FormGroup>
|
||||
</div>
|
||||
)}
|
||||
|
||||
+110
-10
@@ -1,4 +1,7 @@
|
||||
import { generateProposal } from '../../test-helpers/generate-proposals';
|
||||
import {
|
||||
generateProposal,
|
||||
generateProtocolUpgradeProposal,
|
||||
} from '../../test-helpers/generate-proposals';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
@@ -15,6 +18,7 @@ import {
|
||||
nextMonth,
|
||||
} from '../../test-helpers/mocks';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
|
||||
const openProposalClosesNextMonth = generateProposal({
|
||||
id: 'proposal1',
|
||||
@@ -54,12 +58,22 @@ const failedProposalClosedLastMonth = generateProposal({
|
||||
},
|
||||
});
|
||||
|
||||
const renderComponent = (proposals: ProposalQuery['proposal'][]) => (
|
||||
const closedProtocolUpgradeProposal = generateProtocolUpgradeProposal({
|
||||
upgradeBlockHeight: '1',
|
||||
});
|
||||
|
||||
const renderComponent = (
|
||||
proposals: ProposalQuery['proposal'][],
|
||||
protocolUpgradeProposals?: ProtocolUpgradeProposalFieldsFragment[]
|
||||
) => (
|
||||
<Router>
|
||||
<MockedProvider mocks={[networkParamsQueryMock]}>
|
||||
<AppStateProvider>
|
||||
<VegaWalletContext.Provider value={mockWalletContext}>
|
||||
<ProposalsList proposals={proposals} protocolUpgradeProposals={[]} />
|
||||
<ProposalsList
|
||||
proposals={proposals}
|
||||
protocolUpgradeProposals={protocolUpgradeProposals || []}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
</AppStateProvider>
|
||||
</MockedProvider>
|
||||
@@ -143,17 +157,15 @@ describe('Proposals list', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
|
||||
expect(
|
||||
screen.getByTestId('open-proposals-list-filter')
|
||||
).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Filters list by text - party id', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'bvcx' },
|
||||
});
|
||||
@@ -166,7 +178,7 @@ describe('Proposals list', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'proposal1' },
|
||||
});
|
||||
@@ -179,7 +191,7 @@ describe('Proposals list', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'osal1' },
|
||||
});
|
||||
@@ -187,4 +199,92 @@ describe('Proposals list', () => {
|
||||
expect(container.querySelector('#proposal1')).toBeInTheDocument();
|
||||
expect(container.querySelector('#proposal2')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('When filter is used, clear button is visible', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'test' },
|
||||
});
|
||||
expect(screen.getByTestId('clear-filter')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('When clear filter button is used, input is cleared', () => {
|
||||
render(
|
||||
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'test' },
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('clear-filter'));
|
||||
expect((screen.getByTestId('filter-input') as HTMLInputElement).value).toBe(
|
||||
''
|
||||
);
|
||||
});
|
||||
|
||||
it('Displays a toggle for closed proposals if there are both closed governance proposals and closed upgrade proposals', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
[enactedProposalClosedLastWeek],
|
||||
[closedProtocolUpgradeProposal]
|
||||
)
|
||||
);
|
||||
expect(screen.getByTestId('toggle-closed-proposals')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Does not display a toggle for closed proposals if there are only closed upgrade proposals', () => {
|
||||
render(renderComponent([], [closedProtocolUpgradeProposal]));
|
||||
expect(
|
||||
screen.queryByTestId('toggle-closed-proposals')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Does not display a toggle for closed proposals if there are only closed governance proposals', () => {
|
||||
render(renderComponent([enactedProposalClosedLastWeek]));
|
||||
expect(
|
||||
screen.queryByTestId('toggle-closed-proposals')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Does not display a toggle for closed proposals if the proposal filter is engaged', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
[enactedProposalClosedLastWeek],
|
||||
[closedProtocolUpgradeProposal]
|
||||
)
|
||||
);
|
||||
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
|
||||
fireEvent.change(screen.getByTestId('filter-input'), {
|
||||
target: { value: 'test' },
|
||||
});
|
||||
expect(
|
||||
screen.queryByTestId('toggle-closed-proposals')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Displays closed governance proposals by default due to default for the toggle', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
[enactedProposalClosedLastWeek],
|
||||
[closedProtocolUpgradeProposal]
|
||||
)
|
||||
);
|
||||
expect(
|
||||
screen.getByTestId('closed-governance-proposals')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Displays closed upgrade proposals when the toggle is clicked', () => {
|
||||
render(
|
||||
renderComponent(
|
||||
[enactedProposalClosedLastWeek],
|
||||
[closedProtocolUpgradeProposal]
|
||||
)
|
||||
);
|
||||
fireEvent.click(screen.getByText('Network upgrades'));
|
||||
expect(screen.getByTestId('closed-upgrade-proposals')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+106
-15
@@ -7,7 +7,12 @@ import { ProposalsListItem } from '../proposals-list-item';
|
||||
import { ProtocolUpgradeProposalsListItem } from '../protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
|
||||
import { ProposalsListFilter } from '../proposals-list-filter';
|
||||
import Routes from '../../../routes';
|
||||
import { Button, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Button,
|
||||
Toggle,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
|
||||
@@ -54,6 +59,11 @@ export const orderByUpgradeBlockHeight = (
|
||||
['desc', 'desc']
|
||||
);
|
||||
|
||||
enum ClosedProposalsViewOptions {
|
||||
NetworkGovernance = 'networkGovernance',
|
||||
NetworkUpgrades = 'networkUpgrades',
|
||||
}
|
||||
|
||||
export const ProposalsList = ({
|
||||
proposals,
|
||||
protocolUpgradeProposals,
|
||||
@@ -61,6 +71,10 @@ export const ProposalsList = ({
|
||||
}: ProposalsListProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [filterString, setFilterString] = useState('');
|
||||
const [closedProposalsView, setClosedProposalsView] =
|
||||
useState<ClosedProposalsViewOptions>(
|
||||
ClosedProposalsViewOptions.NetworkGovernance
|
||||
);
|
||||
|
||||
const sortedProposals: SortedProposalsProps = useMemo(() => {
|
||||
const initialSorting = proposals.reduce(
|
||||
@@ -109,7 +123,7 @@ export const ProposalsList = ({
|
||||
);
|
||||
return {
|
||||
open: orderByUpgradeBlockHeight(initialSorting.open),
|
||||
closed: orderByUpgradeBlockHeight(initialSorting.closed).reverse(),
|
||||
closed: orderByUpgradeBlockHeight(initialSorting.closed),
|
||||
};
|
||||
}, [protocolUpgradeProposals, lastBlockHeight]);
|
||||
|
||||
@@ -127,6 +141,7 @@ export const ProposalsList = ({
|
||||
marginBottom={false}
|
||||
title={t('pageTitleProposals')}
|
||||
/>
|
||||
|
||||
{DocsLinks && (
|
||||
<div className="xs:justify-self-end" data-testid="new-proposal-link">
|
||||
<ExternalLink href={DocsLinks.PROPOSALS_GUIDE}>
|
||||
@@ -140,6 +155,7 @@ export const ProposalsList = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network. Network upgrades are proposed and approved by validators.`
|
||||
@@ -152,11 +168,26 @@ export const ProposalsList = ({
|
||||
{t(`Find out more about Vega governance`)}
|
||||
</ExternalLink>
|
||||
</p>
|
||||
|
||||
{proposals.length > 0 && (
|
||||
<ProposalsListFilter setFilterString={setFilterString} />
|
||||
<ProposalsListFilter
|
||||
filterString={filterString}
|
||||
setFilterString={(value) => {
|
||||
setFilterString(value);
|
||||
if (value.length > 0) {
|
||||
// If the filter is engaged, ensure the user is viewing governance proposals,
|
||||
// as network upgrades do not have IDs to filter by and will be excluded.
|
||||
setClosedProposalsView(
|
||||
ClosedProposalsViewOptions.NetworkGovernance
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<section className="-mx-4 p-4 mb-8 bg-vega-dark-100">
|
||||
<SubHeading title={t('openProposals')} />
|
||||
|
||||
{sortedProposals.open.length > 0 ||
|
||||
sortedProtocolUpgradeProposals.open.length > 0 ? (
|
||||
<ul data-testid="open-proposals">
|
||||
@@ -166,6 +197,7 @@ export const ProposalsList = ({
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
|
||||
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
|
||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||
))}
|
||||
@@ -176,22 +208,81 @@ export const ProposalsList = ({
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
<section>
|
||||
|
||||
<section className="relative">
|
||||
<SubHeading title={t('closedProposals')} />
|
||||
{sortedProposals.closed.length > 0 ||
|
||||
sortedProtocolUpgradeProposals.closed.length > 0 ? (
|
||||
<ul data-testid="closed-proposals">
|
||||
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
<>
|
||||
{
|
||||
// We need both the closed proposals and closed protocol upgrade
|
||||
// proposals to be present for there to be a toggle. It also gets
|
||||
// hidden if the user has filtered the list, as the upgrade proposals
|
||||
// do not have the necessary fields for filtering.
|
||||
sortedProposals.closed.length > 0 &&
|
||||
sortedProtocolUpgradeProposals.closed.length > 0 &&
|
||||
filterString.length < 1 && (
|
||||
<div
|
||||
className="grid w-full justify-end xl:-mt-12 pb-6"
|
||||
data-testid="toggle-closed-proposals"
|
||||
>
|
||||
<div className="w-[440px]">
|
||||
<Toggle
|
||||
name="closed-proposals-toggle"
|
||||
toggles={[
|
||||
{
|
||||
label: t(
|
||||
ClosedProposalsViewOptions.NetworkGovernance
|
||||
),
|
||||
value: ClosedProposalsViewOptions.NetworkGovernance,
|
||||
},
|
||||
{
|
||||
label: t(
|
||||
ClosedProposalsViewOptions.NetworkUpgrades
|
||||
),
|
||||
value: ClosedProposalsViewOptions.NetworkUpgrades,
|
||||
},
|
||||
]}
|
||||
checkedValue={closedProposalsView}
|
||||
onChange={(e) =>
|
||||
setClosedProposalsView(
|
||||
e.target.value as ClosedProposalsViewOptions
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{sortedProposals.closed.filter(filterPredicate).map((proposal) => (
|
||||
<ProposalsListItem key={proposal?.id} proposal={proposal} />
|
||||
))}
|
||||
</ul>
|
||||
<ul data-testid="closed-proposals">
|
||||
{closedProposalsView ===
|
||||
ClosedProposalsViewOptions.NetworkUpgrades && (
|
||||
<div data-testid="closed-upgrade-proposals">
|
||||
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
|
||||
<ProtocolUpgradeProposalsListItem
|
||||
key={proposal.upgradeBlockHeight}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{closedProposalsView ===
|
||||
ClosedProposalsViewOptions.NetworkGovernance && (
|
||||
<div data-testid="closed-governance-proposals">
|
||||
{sortedProposals.closed
|
||||
.filter(filterPredicate)
|
||||
.map((proposal) => (
|
||||
<ProposalsListItem
|
||||
key={proposal?.id}
|
||||
proposal={proposal}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</ul>
|
||||
</>
|
||||
) : (
|
||||
<p className="mb-0" data-testid="no-closed-proposals">
|
||||
{t('noClosedProposals')}
|
||||
|
||||
+4
-1
@@ -23,7 +23,10 @@ export const RejectedProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('pageTitleRejectedProposals')} />
|
||||
<ProposalsListFilter setFilterString={setFilterString} />
|
||||
<ProposalsListFilter
|
||||
filterString={filterString}
|
||||
setFilterString={setFilterString}
|
||||
/>
|
||||
<section>
|
||||
{proposals.length > 0 ? (
|
||||
<ul data-testid="rejected-proposals">
|
||||
|
||||
+41
-1
@@ -224,7 +224,47 @@ describe('Proposal form vote, validation and enactment deadline', () => {
|
||||
expect(
|
||||
screen.getByTestId('enactment-before-voting-deadline')
|
||||
).toHaveTextContent(
|
||||
'Proposal will fail if enactment is earlier than the voting deadline'
|
||||
'The proposal will fail if enactment is earlier than the voting deadline'
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error text if the vote deadline is set earlier than the minimum allowed', () => {
|
||||
renderComponent();
|
||||
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
||||
fireEvent.change(voteDeadlineInput, { target: { value: 0.01 } });
|
||||
expect(screen.getByTestId('voting-less-than-min')).toHaveTextContent(
|
||||
'The proposal will fail if voting deadline is below the minimum'
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error text if the vote deadline is set later than the maximum allowed', () => {
|
||||
renderComponent();
|
||||
const voteDeadlineInput = screen.getByTestId('proposal-vote-deadline');
|
||||
fireEvent.change(voteDeadlineInput, { target: { value: 100000 } });
|
||||
expect(screen.getByTestId('voting-greater-than-max')).toHaveTextContent(
|
||||
'The proposal will fail if voting deadline is above the maximum'
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error text if the enactment deadline is set earlier than the minimum allowed', () => {
|
||||
renderComponent();
|
||||
const enactmentDeadlineInput = screen.getByTestId(
|
||||
'proposal-enactment-deadline'
|
||||
);
|
||||
fireEvent.change(enactmentDeadlineInput, { target: { value: 0.01 } });
|
||||
expect(screen.getByTestId('enactment-less-than-min')).toHaveTextContent(
|
||||
'The proposal will fail if enactment deadline is below the minimum'
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error text if the enactment deadline is set later than the maximum allowed', () => {
|
||||
renderComponent();
|
||||
const enactmentDeadlineInput = screen.getByTestId(
|
||||
'proposal-enactment-deadline'
|
||||
);
|
||||
fireEvent.change(enactmentDeadlineInput, { target: { value: 100000 } });
|
||||
expect(screen.getByTestId('enactment-greater-than-max')).toHaveTextContent(
|
||||
'The proposal will fail if enactment deadline is above the maximum'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+62
-22
@@ -220,21 +220,41 @@ const EnactmentForm = ({
|
||||
<span data-testid="enactment-date" className="pl-2">
|
||||
{getDateTimeFormat().format(deadlineDates.enactment)}
|
||||
</span>
|
||||
{deadlines.enactment === minEnactmentHours && (
|
||||
<span
|
||||
data-testid="enactment-2-mins-extra"
|
||||
className="block mt-4 font-light"
|
||||
>
|
||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.enactment && deadlines.enactment < deadlines.vote && (
|
||||
<span
|
||||
data-testid="enactment-before-voting-deadline"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
|
||||
</span>
|
||||
{deadlines.enactment && (
|
||||
<>
|
||||
{deadlines.enactment === minEnactmentHours && (
|
||||
<span
|
||||
data-testid="enactment-2-mins-extra"
|
||||
className="block mt-4 font-light"
|
||||
>
|
||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.enactment < deadlines.vote && (
|
||||
<span
|
||||
data-testid="enactment-before-voting-deadline"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.enactment < minEnactmentHours && (
|
||||
<span
|
||||
data-testid="enactment-less-than-min"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfEnactmentIsBelowTheMinimumDeadline')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.enactment > maxEnactmentHours && (
|
||||
<span
|
||||
data-testid="enactment-greater-than-max"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfEnactmentIsAboveTheMaximumDeadline')}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
@@ -500,13 +520,33 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
||||
<span data-testid="voting-date" className="pl-2">
|
||||
{getDateTimeFormat().format(deadlineDates.vote)}
|
||||
</span>
|
||||
{deadlines.vote === minVoteHours && (
|
||||
<span
|
||||
data-testid="voting-2-mins-extra"
|
||||
className="block mt-4 font-light"
|
||||
>
|
||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||
</span>
|
||||
{deadlines.vote && (
|
||||
<>
|
||||
{deadlines.vote === minVoteHours && (
|
||||
<span
|
||||
data-testid="voting-2-mins-extra"
|
||||
className="block mt-4 font-light"
|
||||
>
|
||||
{t('ThisWillAdd2MinutesToAllowTimeToConfirmInWallet')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.vote < minVoteHours && (
|
||||
<span
|
||||
data-testid="voting-less-than-min"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfVotingIsBelowTheMinimumDeadline')}
|
||||
</span>
|
||||
)}
|
||||
{deadlines.vote > maxVoteHours && (
|
||||
<span
|
||||
data-testid="voting-greater-than-max"
|
||||
className="block mt-4 text-vega-pink"
|
||||
>
|
||||
{t('ProposalWillFailIfVotingIsAboveTheMaximumDeadline')}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { captureMessage } from '@sentry/minimal';
|
||||
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { VoteValue } from '@vegaprotocol/types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useUserVoteQuery } from './__generated__/Vote';
|
||||
import type { FinalizedVote } from '@vegaprotocol/proposals';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import type { FinalizedVote } from '@vegaprotocol/proposals';
|
||||
|
||||
export enum VoteState {
|
||||
NotCast = 'NotCast',
|
||||
@@ -45,21 +44,23 @@ export function useUserVote(
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (finalizedVote?.vote.value) {
|
||||
if (finalizedVote?.vote.value && finalizedVote.pubKey === pubKey) {
|
||||
setUserVote(finalizedVote);
|
||||
} else if (data?.party?.votesConnection?.edges) {
|
||||
// This sets the vote (if any) when the user first loads the page
|
||||
setUserVote(
|
||||
removePaginationWrapper(data?.party?.votesConnection?.edges).find(
|
||||
({ proposalId: pId }) => proposalId === pId
|
||||
)
|
||||
);
|
||||
} else if (data?.party?.votesConnection?.edges && pubKey) {
|
||||
const vote = removePaginationWrapper(
|
||||
data?.party?.votesConnection?.edges
|
||||
).find(({ proposalId: pId }) => proposalId === pId);
|
||||
|
||||
if (vote) {
|
||||
setUserVote({ ...vote, pubKey });
|
||||
}
|
||||
}
|
||||
}, [
|
||||
finalizedVote?.vote.value,
|
||||
data?.party?.votesConnection?.edges,
|
||||
finalizedVote,
|
||||
proposalId,
|
||||
pubKey,
|
||||
]);
|
||||
|
||||
// If user vote changes update the vote state
|
||||
@@ -94,6 +95,8 @@ export function useUserVote(
|
||||
return {
|
||||
voteState,
|
||||
userVote,
|
||||
voteDatetime: userVote ? new Date(userVote.vote.datetime) : null,
|
||||
voteDatetime: userVote?.vote?.datetime
|
||||
? new Date(userVote.vote.datetime)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { ProposalNotFound } from '../components/proposal-not-found';
|
||||
import { useProposalQuery } from './__generated__/Proposal';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import { ENV } from '../../../config';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
|
||||
|
||||
export const ProposalContainer = () => {
|
||||
const params = useParams<{ proposalId: string }>();
|
||||
@@ -20,15 +22,36 @@ export const ProposalContainer = () => {
|
||||
skip: !params.proposalId,
|
||||
});
|
||||
|
||||
const {
|
||||
data: newMarketData,
|
||||
loading: newMarketLoading,
|
||||
error: newMarketError,
|
||||
} = useDataProvider({
|
||||
dataProvider: marketInfoWithDataProvider,
|
||||
skipUpdates: true,
|
||||
variables: {
|
||||
marketId: data?.proposal?.id || '',
|
||||
skip: !data?.proposal?.id,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(refetch, 1000);
|
||||
const interval = setInterval(refetch, 2000);
|
||||
return () => clearInterval(interval);
|
||||
}, [refetch]);
|
||||
|
||||
return (
|
||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||
<AsyncRenderer
|
||||
loading={loading || newMarketLoading}
|
||||
error={error || newMarketError}
|
||||
data={newMarketData ? { newMarketData, data } : data}
|
||||
>
|
||||
{data?.proposal ? (
|
||||
<Proposal proposal={data.proposal} restData={restData} />
|
||||
<Proposal
|
||||
proposal={data.proposal}
|
||||
restData={restData}
|
||||
newMarketData={newMarketData}
|
||||
/>
|
||||
) : (
|
||||
<ProposalNotFound />
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as faker from 'faker';
|
||||
import isArray from 'lodash/isArray';
|
||||
@@ -6,6 +7,40 @@ import mergeWith from 'lodash/mergeWith';
|
||||
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { ProposalQuery } from '../proposal/__generated__/Proposal';
|
||||
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
|
||||
|
||||
export function generateProtocolUpgradeProposal(
|
||||
override: PartialDeep<ProtocolUpgradeProposalFieldsFragment> = {}
|
||||
): ProtocolUpgradeProposalFieldsFragment {
|
||||
const defaultProposal: ProtocolUpgradeProposalFieldsFragment = {
|
||||
__typename: 'ProtocolUpgradeProposal',
|
||||
upgradeBlockHeight: '3917600',
|
||||
vegaReleaseTag: 'v0.71.6',
|
||||
approvers: [
|
||||
'0ac70c4ccc7f961614fe49b93e639ddf916269b7dcf8391db264cefeadf5a6b7',
|
||||
'63a1755006642bda9ab1bfa84660f944d30a113d1609590ca90c50b24aede472',
|
||||
'68ed0770fc3e67b74d09c05443243d27e29a8513dc0e8628beb98338cd509159',
|
||||
'a6e6f7daf8610f9242ab6ab46b394f6fb79cf9533d48051ca7a2f142b8b700a8',
|
||||
'aad2be546ba83cbcab4c1d57ebe22b4a942f294f54333f1a7c2c9ef0e9fe19bb',
|
||||
'acc55c7205cfcd5480e0235acab56a01487a39dc858a641fc04df6ba016870ee',
|
||||
'b7e500deb24cc19bd6ebb2311997f0904ca0d9e51541249e9650ab41fd8ac376',
|
||||
'cf295dff6d9506e8a905d168a44dfcff2f64bd0a6671783a469f8322959c62e2',
|
||||
'f4686749895bf51c6df4092ef6be4279c384a3c380c24ea7a2fd20afc602a35d',
|
||||
],
|
||||
status:
|
||||
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED,
|
||||
};
|
||||
|
||||
return mergeWith<
|
||||
ProtocolUpgradeProposalFieldsFragment,
|
||||
PartialDeep<ProtocolUpgradeProposalFieldsFragment>
|
||||
>(defaultProposal, override, (objValue, srcValue) => {
|
||||
if (!isArray(objValue)) {
|
||||
return;
|
||||
}
|
||||
return srcValue;
|
||||
});
|
||||
}
|
||||
|
||||
export function generateProposal(
|
||||
override: PartialDeep<ProposalQuery['proposal']> = {}
|
||||
|
||||
+8
-1
@@ -48,15 +48,22 @@ export const EpochIndividualRewards = ({
|
||||
return removePaginationWrapper(data.party.rewardsConnection.edges);
|
||||
}, [data]);
|
||||
|
||||
const epochRewardSummaries = useMemo(() => {
|
||||
if (!data?.epochRewardSummaries) return [];
|
||||
|
||||
return removePaginationWrapper(data.epochRewardSummaries.edges);
|
||||
}, [data]);
|
||||
|
||||
const epochIndividualRewardSummaries = useMemo(() => {
|
||||
if (!data?.party) return [];
|
||||
return generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId,
|
||||
epochRewardSummaries,
|
||||
page,
|
||||
size: EPOCHS_PAGE_SIZE,
|
||||
});
|
||||
}, [data?.party, epochId, page, rewards]);
|
||||
}, [data?.party, epochId, epochRewardSummaries, page, rewards]);
|
||||
|
||||
const refetchData = useCallback(
|
||||
async (toPage?: number) => {
|
||||
|
||||
+98
-4
@@ -65,7 +65,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
|
||||
it('should return an empty array if no rewards are provided', () => {
|
||||
expect(
|
||||
generateEpochIndividualRewardsList({ rewards: [], epochId: 1 })
|
||||
generateEpochIndividualRewardsList({
|
||||
rewards: [],
|
||||
epochId: 1,
|
||||
epochRewardSummaries: [],
|
||||
})
|
||||
).toEqual([
|
||||
{
|
||||
epoch: 1,
|
||||
@@ -78,6 +82,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
const result = generateEpochIndividualRewardsList({
|
||||
rewards: [rewardWrongType],
|
||||
epochId: 1,
|
||||
epochRewardSummaries: [],
|
||||
});
|
||||
|
||||
expect(result).toEqual([
|
||||
@@ -92,6 +97,15 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
const result = generateEpochIndividualRewardsList({
|
||||
rewards: [reward1],
|
||||
epochId: 1,
|
||||
epochRewardSummaries: [
|
||||
{
|
||||
__typename: 'EpochRewardSummary',
|
||||
epoch: 1,
|
||||
assetId: 'usd',
|
||||
amount: '100000',
|
||||
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result[0]).toEqual({
|
||||
@@ -134,7 +148,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
|
||||
it('should return an array sorted by epoch descending', () => {
|
||||
const rewards = [reward1, reward2, reward3, reward4];
|
||||
const result1 = generateEpochIndividualRewardsList({ rewards, epochId: 2 });
|
||||
const result1 = generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId: 2,
|
||||
epochRewardSummaries: [],
|
||||
});
|
||||
|
||||
expect(result1[0].epoch).toEqual(2);
|
||||
expect(result1[1].epoch).toEqual(1);
|
||||
@@ -143,6 +161,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
const result2 = generateEpochIndividualRewardsList({
|
||||
rewards: reorderedRewards,
|
||||
epochId: 2,
|
||||
epochRewardSummaries: [],
|
||||
});
|
||||
|
||||
expect(result2[0].epoch).toEqual(2);
|
||||
@@ -151,7 +170,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
|
||||
it('correctly calculates the total value of rewards for an asset', () => {
|
||||
const rewards = [reward1, reward4];
|
||||
const result = generateEpochIndividualRewardsList({ rewards, epochId: 1 });
|
||||
const result = generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId: 1,
|
||||
epochRewardSummaries: [],
|
||||
});
|
||||
|
||||
expect(result[0].rewards[0].totalAmount).toEqual('200');
|
||||
});
|
||||
@@ -159,7 +182,11 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
it('returns data in the expected shape', () => {
|
||||
// Just sanity checking the whole structure here
|
||||
const rewards = [reward1, reward2, reward3, reward4];
|
||||
const result = generateEpochIndividualRewardsList({ rewards, epochId: 2 });
|
||||
const result = generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId: 2,
|
||||
epochRewardSummaries: [],
|
||||
});
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
@@ -273,6 +300,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
const resultPageOne = generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId: 3,
|
||||
epochRewardSummaries: [],
|
||||
page: 1,
|
||||
size: 2,
|
||||
});
|
||||
@@ -386,6 +414,7 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
const resultPageTwo = generateEpochIndividualRewardsList({
|
||||
rewards,
|
||||
epochId: 3,
|
||||
epochRewardSummaries: [],
|
||||
page: 2,
|
||||
size: 2,
|
||||
});
|
||||
@@ -429,4 +458,69 @@ describe('generateEpochIndividualRewardsList', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('correctly calculates the percentage of two or more rewards by referencing the total rewards amount', () => {
|
||||
const result = generateEpochIndividualRewardsList({
|
||||
rewards: [
|
||||
// reward1 is 100 usd, which is 10% of the total rewards amount
|
||||
reward1,
|
||||
{
|
||||
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||
amount: '200',
|
||||
percentageOfTotal: '0.2',
|
||||
receivedAt: new Date(),
|
||||
asset: { id: 'usd', symbol: 'USD', name: 'USD', decimals: 6 },
|
||||
party: { id: 'blah' },
|
||||
epoch: { id: '1' },
|
||||
},
|
||||
],
|
||||
epochId: 1,
|
||||
epochRewardSummaries: [
|
||||
{
|
||||
__typename: 'EpochRewardSummary',
|
||||
epoch: 1,
|
||||
assetId: 'usd',
|
||||
amount: '1000',
|
||||
rewardType: AccountType.ACCOUNT_TYPE_GLOBAL_REWARD,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(result[0]).toEqual({
|
||||
epoch: 1,
|
||||
rewards: [
|
||||
{
|
||||
asset: 'USD',
|
||||
decimals: 6,
|
||||
totalAmount: '300',
|
||||
rewardTypes: {
|
||||
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
|
||||
amount: '300',
|
||||
percentageOfTotal: '30',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
[AccountType.ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS]: {
|
||||
amount: '0',
|
||||
percentageOfTotal: '0',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+27
-11
@@ -1,6 +1,9 @@
|
||||
import { BigNumber } from '../../../lib/bignumber';
|
||||
import { RowAccountTypes } from '../shared-rewards-table-assets/shared-rewards-table-assets';
|
||||
import type { RewardFieldsFragment } from '../home/__generated__/Rewards';
|
||||
import type {
|
||||
EpochRewardSummaryFieldsFragment,
|
||||
RewardFieldsFragment,
|
||||
} from '../home/__generated__/Rewards';
|
||||
import type { AccountType } from '@vegaprotocol/types';
|
||||
import { calculateEpochOffset } from '../../../lib/epoch-pagination';
|
||||
|
||||
@@ -32,11 +35,13 @@ const emptyRowAccountTypes = accountTypes.map((type) => [
|
||||
export const generateEpochIndividualRewardsList = ({
|
||||
rewards,
|
||||
epochId,
|
||||
epochRewardSummaries,
|
||||
page = 1,
|
||||
size = 10,
|
||||
}: {
|
||||
rewards: RewardFieldsFragment[];
|
||||
epochId: number;
|
||||
epochRewardSummaries: EpochRewardSummaryFieldsFragment[];
|
||||
page?: number;
|
||||
size?: number;
|
||||
}) => {
|
||||
@@ -54,6 +59,7 @@ export const generateEpochIndividualRewardsList = ({
|
||||
const epochIndividualRewards = rewards.reduce((acc, reward) => {
|
||||
const epochId = reward.epoch.id;
|
||||
const assetName = reward.asset.name;
|
||||
const assetId = reward.asset.id;
|
||||
const assetDecimals = reward.asset.decimals;
|
||||
const rewardType = reward.rewardType;
|
||||
const amount = reward.amount;
|
||||
@@ -70,6 +76,14 @@ export const generateEpochIndividualRewardsList = ({
|
||||
|
||||
const epoch = acc.get(epochId);
|
||||
|
||||
// matchingTotalReward is the total awarded for all users for the reward type in the epoch of the asset
|
||||
const matchingTotalRewardAmount = epochRewardSummaries.find(
|
||||
(summary) =>
|
||||
summary.epoch === Number(epochId) &&
|
||||
summary.assetId === assetId &&
|
||||
summary.rewardType === rewardType
|
||||
)?.amount;
|
||||
|
||||
let asset = epoch?.rewards.find((r) => r.asset === assetName);
|
||||
|
||||
if (!asset) {
|
||||
@@ -86,22 +100,24 @@ export const generateEpochIndividualRewardsList = ({
|
||||
asset.rewardTypes[rewardType] = { amount, percentageOfTotal };
|
||||
} else {
|
||||
const previousAmount = asset.rewardTypes[rewardType]?.amount;
|
||||
const previousPercentageOfTotal =
|
||||
asset.rewardTypes[rewardType]?.percentageOfTotal;
|
||||
const newAmount = previousAmount
|
||||
? new BigNumber(previousAmount).plus(amount).toString()
|
||||
: amount;
|
||||
|
||||
asset.rewardTypes[rewardType] = {
|
||||
amount: previousAmount
|
||||
? new BigNumber(previousAmount).plus(amount).toString()
|
||||
: amount,
|
||||
percentageOfTotal: previousPercentageOfTotal
|
||||
? new BigNumber(previousPercentageOfTotal)
|
||||
.plus(percentageOfTotal)
|
||||
amount: newAmount,
|
||||
percentageOfTotal: matchingTotalRewardAmount
|
||||
? new BigNumber(newAmount)
|
||||
.dividedBy(matchingTotalRewardAmount)
|
||||
.multipliedBy(100)
|
||||
.toString()
|
||||
: percentageOfTotal,
|
||||
: // this should never be reached, if there's an individual reward there should
|
||||
// always be a reward total from the api too, but set it as a fallback just in case
|
||||
percentageOfTotal,
|
||||
};
|
||||
}
|
||||
|
||||
// totalAmount is the sum of all rewardTypes amounts
|
||||
// totalAmount is the sum of all individual rewardTypes amounts
|
||||
asset.totalAmount = Object.values(asset.rewardTypes).reduce(
|
||||
(sum, rewardType) => {
|
||||
return new BigNumber(sum).plus(rewardType.amount).toString();
|
||||
|
||||
@@ -22,6 +22,13 @@ fragment DelegationFields on Delegation {
|
||||
epoch
|
||||
}
|
||||
|
||||
fragment EpochRewardSummaryFields on EpochRewardSummary {
|
||||
epoch
|
||||
assetId
|
||||
amount
|
||||
rewardType
|
||||
}
|
||||
|
||||
query Rewards(
|
||||
$partyId: ID!
|
||||
$fromEpoch: Int
|
||||
@@ -50,13 +57,16 @@ query Rewards(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment EpochRewardSummaryFields on EpochRewardSummary {
|
||||
epoch
|
||||
assetId
|
||||
amount
|
||||
rewardType
|
||||
epochRewardSummaries(
|
||||
filter: { fromEpoch: $fromEpoch, toEpoch: $toEpoch }
|
||||
pagination: $rewardsPagination
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
...EpochRewardSummaryFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query EpochAssetsRewards(
|
||||
|
||||
@@ -7,6 +7,8 @@ export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.Ac
|
||||
|
||||
export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number };
|
||||
|
||||
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
|
||||
|
||||
export type RewardsQueryVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
fromEpoch?: Types.InputMaybe<Types.Scalars['Int']>;
|
||||
@@ -16,9 +18,7 @@ export type RewardsQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null };
|
||||
|
||||
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
|
||||
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epochRewardSummaries?: { __typename?: 'EpochRewardSummaryConnection', edges?: Array<{ __typename?: 'EpochRewardSummaryEdge', node: { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType } } | null> | null } | null };
|
||||
|
||||
export type EpochAssetsRewardsQueryVariables = Types.Exact<{
|
||||
epochRewardSummariesFilter?: Types.InputMaybe<Types.RewardSummaryFilter>;
|
||||
@@ -102,9 +102,20 @@ export const RewardsDocument = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
epochRewardSummaries(
|
||||
filter: {fromEpoch: $fromEpoch, toEpoch: $toEpoch}
|
||||
pagination: $rewardsPagination
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
...EpochRewardSummaryFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${RewardFieldsFragmentDoc}
|
||||
${DelegationFieldsFragmentDoc}`;
|
||||
${DelegationFieldsFragmentDoc}
|
||||
${EpochRewardSummaryFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useRewardsQuery__
|
||||
|
||||
+8
@@ -36,6 +36,7 @@ import {
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { VALIDATOR_LOGO_MAP } from './logo-map';
|
||||
import { getMultisigStatusInfo } from '../../../../lib/get-multisig-status-info';
|
||||
|
||||
interface CanonisedConsensusNodeProps {
|
||||
id: string;
|
||||
@@ -137,6 +138,10 @@ export const ConsensusValidatorsTable = ({
|
||||
[totalStake]
|
||||
);
|
||||
|
||||
const multisigStatus = previousEpochData
|
||||
? getMultisigStatusInfo(previousEpochData)
|
||||
: undefined;
|
||||
|
||||
const allNodesInPreviousEpoch = removePaginationWrapper(
|
||||
previousEpochData?.epoch.validatorsConnection?.edges
|
||||
);
|
||||
@@ -223,6 +228,8 @@ export const ConsensusValidatorsTable = ({
|
||||
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
|
||||
? formatNumberPercentage(new BigNumber(userStakeShare), 2)
|
||||
: undefined,
|
||||
[ValidatorFields.MULTISIG_ERROR]:
|
||||
multisigStatus?.showMultisigStatusError,
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -332,6 +339,7 @@ export const ConsensusValidatorsTable = ({
|
||||
data,
|
||||
decimals,
|
||||
hideTopThird,
|
||||
multisigStatus?.showMultisigStatusError,
|
||||
previousEpochData,
|
||||
thirdOfTotalStake,
|
||||
validatorsView,
|
||||
|
||||
@@ -39,6 +39,7 @@ export enum ValidatorFields {
|
||||
STAKED_BY_USER = 'stakedByUser',
|
||||
PENDING_USER_STAKE = 'pendingUserStake',
|
||||
USER_STAKE_SHARE = 'userStakeShare',
|
||||
MULTISIG_ERROR = 'multisigError',
|
||||
}
|
||||
|
||||
export const addUserDataToValidator = (
|
||||
@@ -326,6 +327,7 @@ interface TotalPenaltiesRendererProps {
|
||||
overstakedAmount: string;
|
||||
overstakingPenalty: string;
|
||||
totalPenalties: string;
|
||||
multisigError?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -344,10 +346,11 @@ export const TotalPenaltiesRenderer = ({
|
||||
<div data-testid="overstaked-penalty-tooltip">
|
||||
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
||||
</div>
|
||||
<div data-testid="total-penalty-tooltip">
|
||||
{t('totalPenalties')}:{' '}
|
||||
<span className="font-bold">{data.totalPenalties}</span>
|
||||
</div>
|
||||
{data.multisigError && (
|
||||
<div data-testid="multisig-error-tooltip">
|
||||
{t('multisigPenalty')}: 100%
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -107,7 +107,7 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
|
||||
<div className="flex items-center gap-1">
|
||||
<Icon name={'chevron-left'} />
|
||||
<Link className="underline" to={Routes.VALIDATORS}>
|
||||
{t('All validators')}
|
||||
{t('AllValidators')}
|
||||
</Link>
|
||||
</div>
|
||||
<Heading
|
||||
|
||||
@@ -7,31 +7,30 @@ import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
getFeeLevels,
|
||||
sumLiquidityCommitted,
|
||||
marketLiquidityDataProvider,
|
||||
lpAggregatedDataProvider,
|
||||
} from '@vegaprotocol/liquidity';
|
||||
import type { MarketLpQuery } from '@vegaprotocol/liquidity';
|
||||
import { marketWithDataProvider } from '@vegaprotocol/markets';
|
||||
import type { MarketWithData } from '@vegaprotocol/markets';
|
||||
|
||||
import { Market } from './market';
|
||||
import { Header } from './header';
|
||||
import { LPProvidersGrid } from './providers';
|
||||
|
||||
const formatMarket = (data: MarketLpQuery) => {
|
||||
const formatMarket = (market: MarketWithData) => {
|
||||
return {
|
||||
name: data?.market?.tradableInstrument.instrument.name,
|
||||
name: market?.tradableInstrument.instrument.name,
|
||||
symbol:
|
||||
data?.market?.tradableInstrument.instrument.product.settlementAsset
|
||||
.symbol,
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.symbol,
|
||||
settlementAsset:
|
||||
data?.market?.tradableInstrument.instrument.product.settlementAsset,
|
||||
targetStake: data?.market?.data?.targetStake,
|
||||
tradingMode: data?.market?.data?.marketTradingMode,
|
||||
trigger: data?.market?.data?.trigger,
|
||||
market?.tradableInstrument.instrument.product.settlementAsset,
|
||||
targetStake: market?.data?.targetStake,
|
||||
tradingMode: market?.data?.marketTradingMode,
|
||||
trigger: market?.data?.trigger,
|
||||
};
|
||||
};
|
||||
|
||||
export const lpDataProvider = makeDerivedDataProvider(
|
||||
[marketLiquidityDataProvider, lpAggregatedDataProvider],
|
||||
[marketWithDataProvider, lpAggregatedDataProvider],
|
||||
([market, lpAggregatedData]) => ({
|
||||
market: { ...formatMarket(market) },
|
||||
liquidityProviders: lpAggregatedData || [],
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Static
|
||||
|
||||
A static CDN for Vega assets
|
||||
A static CDN for Vega assets: `static.vega.xyz`
|
||||
|
||||
prepare assets by running: `yarn nx build static`
|
||||
|
||||
@@ -26,27 +26,27 @@
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:first-child {
|
||||
animation-delay: -50ms;
|
||||
animation-delay: -0.1s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
animation-delay: 0.3s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(3) {
|
||||
animation-delay: -0.6s;
|
||||
animation-delay: -0.45s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(4) {
|
||||
animation-delay: 0.4s;
|
||||
animation-delay: 1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(5) {
|
||||
animation-delay: -0.5s;
|
||||
animation-delay: -0.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(6) {
|
||||
animation-delay: 0.3s;
|
||||
animation-delay: 0.9s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(7) {
|
||||
@@ -54,11 +54,11 @@
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(8) {
|
||||
animation-delay: 2s;
|
||||
animation-delay: 1.6s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(9) {
|
||||
animation-delay: -0.9s;
|
||||
animation-delay: -0.45s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(10) {
|
||||
@@ -66,7 +66,7 @@
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(11) {
|
||||
animation-delay: -0.55s;
|
||||
animation-delay: -2.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(12) {
|
||||
@@ -74,21 +74,57 @@
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(13) {
|
||||
animation-delay: -0.65s;
|
||||
animation-delay: -1.95s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(14) {
|
||||
animation-delay: 0.7s;
|
||||
animation-delay: 2.8s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(15) {
|
||||
animation-delay: -3.75s;
|
||||
animation-delay: -0.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(16) {
|
||||
animation-delay: 1.6s;
|
||||
animation-delay: 4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(17) {
|
||||
animation-delay: -0.85s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(18) {
|
||||
animation-delay: 1.8s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(19) {
|
||||
animation-delay: -1.9s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(20) {
|
||||
animation-delay: 5s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(21) {
|
||||
animation-delay: -5.25s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(22) {
|
||||
animation-delay: 4.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(23) {
|
||||
animation-delay: -5.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(24) {
|
||||
animation-delay: 4.8s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(25) {
|
||||
animation-delay: -5s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item {
|
||||
animation: flickering 0.4s linear infinite alternate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
.pre-loader {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.loader-item {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: black;
|
||||
}
|
||||
.pre-loader-center {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.pre-loader-wrapper {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@for $i from 0 through 25 {
|
||||
.loader-item:nth-child(#{$i}) {
|
||||
@if $i % 2 == 0 {
|
||||
animation-delay: #{$i * 50 * random(5)}ms;
|
||||
animation-direction: reverse;
|
||||
} @else {
|
||||
animation-delay: #{$i * -50 * random(5)}ms;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
}
|
||||
}
|
||||
.loader-item {
|
||||
animation: flickering 0.4s linear alternate infinite;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
html.dark {
|
||||
.pre-loader {
|
||||
.loader-item {
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
||||
NX_SENTRY_DSN=https://dummy@o999999.ingest.sentry.io/9999999
|
||||
|
||||
# Expose some env vars to cypress environment for market setup
|
||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #region consts
|
||||
const asset = 'asset';
|
||||
const assetColId = '[col-id="asset.symbol"]';
|
||||
const assetDetailsDialog = 'dialog-content';
|
||||
const assetRow = 'key-value-table-row';
|
||||
const contractAddress = '7_value';
|
||||
@@ -108,7 +108,7 @@ beforeEach(() => {
|
||||
|
||||
const visitPortfolioAndClickAsset = (assetName: string) => {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId(asset).contains(assetName).click();
|
||||
cy.get(assetColId).contains(assetName).click();
|
||||
};
|
||||
|
||||
const testTooltip = (index: number, testId: string, tooltip: string) => {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
describe('charts', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
cy.getByTestId('Depth').click();
|
||||
});
|
||||
|
||||
it('can see market depth chart', () => {
|
||||
// 6006-DEPC-001
|
||||
cy.getByTestId('tab-depth').should('be.visible');
|
||||
cy.get('.depth-chart-module_canvas__260De').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -450,3 +450,17 @@ describe('Closed markets', { tags: '@smoke' }, () => {
|
||||
.should('have.text', 'View on Explorer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('no closed markets', { tags: '@smoke', testIsolation: true }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Closed markets"]').click();
|
||||
});
|
||||
|
||||
it('can see no markets message', () => {
|
||||
// 6001-MARK-034
|
||||
cy.getByTestId('tab-closed-markets').should('contain.text', 'No markets');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
const dialogContent = 'dialog-content';
|
||||
const nodeHealth = 'node-health';
|
||||
const statusIncidentsLink = 'footer [data-testid=external-link]';
|
||||
|
||||
describe('home', { tags: '@regression' }, () => {
|
||||
before(() => {
|
||||
cy.clearAllLocalStorage();
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
@@ -76,23 +74,14 @@ describe('home', { tags: '@regression' }, () => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
// 0006-NETW-002
|
||||
// 0006-NETW-003
|
||||
// 0006-NETW-011
|
||||
it('switch to fairground network and check status & incidents link', () => {
|
||||
// 0006-NETW-002
|
||||
// 0006-NETW-003
|
||||
cy.getByTestId('navigation')
|
||||
.find('[data-testid="network-switcher"]')
|
||||
.should('have.text', 'Custom')
|
||||
.click();
|
||||
cy.getByTestId('network-item').contains('Fairground testnet').click();
|
||||
cy.get('[aria-haspopup="menu"]').should('contain.text', 'Fairground');
|
||||
cy.url().should('include', 'fairground.wtf');
|
||||
cy.contains('Continue').click();
|
||||
cy.get(statusIncidentsLink)
|
||||
.children('span')
|
||||
.should('have.text', 'Mainnet status & incidents');
|
||||
cy.get(statusIncidentsLink)
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', 'https://blog.vega.xyz/tagged/vega-incident-reports');
|
||||
cy.getByTestId('network-item').contains('Fairground testnet');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import type { MarketsQuery } from '@vegaprotocol/markets';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-all-markets"] .ag-center-cols-container .ag-row';
|
||||
const colInstrumentCode = '[col-id="tradableInstrument.instrument.code"]';
|
||||
|
||||
describe('markets all table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -60,7 +63,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
// 6001-MARK-035
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="tradableInstrument.instrument.code"]')
|
||||
.find(colInstrumentCode)
|
||||
.should('have.text', 'SOLUSD');
|
||||
|
||||
// 6001-MARK-036
|
||||
@@ -155,6 +158,7 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('able to open and sort full market list - market page', () => {
|
||||
// 6001-MARK-064
|
||||
const ExpectedSortedMarkets = [
|
||||
'AAPL.MF21',
|
||||
'BTCUSD.MF21',
|
||||
@@ -167,8 +171,38 @@ describe('markets all table', { tags: '@smoke' }, () => {
|
||||
cy.get('.ag-header-cell-label').contains('Market').click(); // sort by market name
|
||||
for (let i = 0; i < ExpectedSortedMarkets.length; i++) {
|
||||
cy.get(`[row-index=${i}]`)
|
||||
.find('[col-id="tradableInstrument.instrument.code"]')
|
||||
.find(colInstrumentCode)
|
||||
.should('have.text', ExpectedSortedMarkets[i]);
|
||||
}
|
||||
});
|
||||
|
||||
it('can drag and drop columns', () => {
|
||||
// 6001-MARK-065
|
||||
cy.get('.ag-overlay-loading-wrapper').should('not.be.visible');
|
||||
cy.get(colInstrumentCode)
|
||||
.realMouseDown()
|
||||
.realMouseMove(700, 15)
|
||||
.realMouseUp();
|
||||
cy.get(colInstrumentCode).should(($element) => {
|
||||
const attributeValue = $element.attr('aria-colindex');
|
||||
expect(attributeValue).not.to.equal('1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('no all markets', { tags: '@smoke', testIsolation: true }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
const markets: MarketsQuery = {};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Markets', markets);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/all');
|
||||
});
|
||||
|
||||
it('can see no markets message', () => {
|
||||
// 6001-MARK-048
|
||||
cy.getByTestId('tab-all-markets').should('contain.text', 'No markets');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { MarketTradingModeMapping } from '@vegaprotocol/types';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
|
||||
const marketInfoBtn = 'Info';
|
||||
const row = 'key-value-table-row';
|
||||
const marketTitle = 'accordion-title';
|
||||
const externalLink = 'external-link';
|
||||
const accordionContent = 'accordion-content';
|
||||
const blockExplorerLink = 'block-explorer-link';
|
||||
const dialogClose = 'dialog-close';
|
||||
const dialogContent = 'dialog-content';
|
||||
const externalLink = 'external-link';
|
||||
const githubLink = 'github-link';
|
||||
const liquidityLink = 'view-liquidity-link';
|
||||
const marketInfoBtn = 'Info';
|
||||
const marketTitle = 'accordion-title';
|
||||
const providerName = 'provider-name';
|
||||
const oracleBannerStatus = 'oracle-banner-status';
|
||||
const oracleBannerDialogTrigger = 'oracle-banner-dialog-trigger';
|
||||
const oracleFullProfile = 'oracle-full-profile';
|
||||
const row = 'key-value-table-row';
|
||||
const verifiedProofs = 'verified-proofs';
|
||||
|
||||
describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -17,12 +20,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
before(() => {
|
||||
cy.mockTradingPage(
|
||||
MarketState.STATE_ACTIVE,
|
||||
undefined,
|
||||
undefined,
|
||||
'COMPROMISED'
|
||||
);
|
||||
cy.mockTradingPage(MarketState.STATE_ACTIVE);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
@@ -30,16 +28,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
cy.wait('@MarketInfo');
|
||||
});
|
||||
|
||||
it('show oracle banner', () => {
|
||||
cy.getByTestId(marketTitle).contains('Oracle').click();
|
||||
cy.getByTestId(oracleBannerStatus).should('contain.text', 'COMPROMISED');
|
||||
cy.getByTestId(oracleBannerDialogTrigger)
|
||||
.should('contain.text', 'Show more')
|
||||
.click();
|
||||
cy.getByTestId(oracleFullProfile).should('exist');
|
||||
});
|
||||
|
||||
it('current fees displayed', () => {
|
||||
// 6002-MDET-101
|
||||
cy.getByTestId(marketTitle).contains('Current fees').click();
|
||||
validateMarketDataRow(0, 'Maker Fee', '0.02%');
|
||||
validateMarketDataRow(1, 'Infrastructure Fee', '0.05%');
|
||||
@@ -48,6 +38,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('market price', () => {
|
||||
// 6002-MDET-102
|
||||
cy.getByTestId(marketTitle).contains('Market price').click();
|
||||
validateMarketDataRow(0, 'Mark Price', '46,126.90058');
|
||||
validateMarketDataRow(1, 'Best Bid Price', '44,126.90058 ');
|
||||
@@ -56,6 +47,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('market volume displayed', () => {
|
||||
// 6002-MDET-103
|
||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||
validateMarketDataRow(1, 'Open Interest', '-');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||
@@ -65,11 +57,13 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('insurance pool displayed', () => {
|
||||
// 6002-MDET-104
|
||||
cy.getByTestId(marketTitle).contains('Insurance pool').click();
|
||||
validateMarketDataRow(0, 'Balance', '0');
|
||||
});
|
||||
|
||||
it('key details displayed', () => {
|
||||
// 6002-MDET-201
|
||||
cy.getByTestId(marketTitle).contains('Key details').click();
|
||||
|
||||
validateMarketDataRow(0, 'Name', 'BTCUSD Monthly (30 Jun 2022)');
|
||||
@@ -85,6 +79,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('instrument displayed', () => {
|
||||
// 6002-MDET-202
|
||||
cy.getByTestId(marketTitle).contains('Instrument').click();
|
||||
|
||||
validateMarketDataRow(0, 'Market Name', 'BTCUSD Monthly (30 Jun 2022)');
|
||||
@@ -93,7 +88,30 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(3, 'Quote Name', 'BTC');
|
||||
});
|
||||
|
||||
it('oracle displayed', () => {
|
||||
// 6002-MDET-203
|
||||
cy.getByTestId(marketTitle).contains('Oracle').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId(providerName)
|
||||
.and('contain', 'Another oracle');
|
||||
|
||||
cy.getByTestId(providerName).should('be.visible').click();
|
||||
cy.getByTestId(dialogContent)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId(blockExplorerLink).contains('Block explorer');
|
||||
cy.getByTestId(githubLink).contains('Oracle repository');
|
||||
});
|
||||
cy.getByTestId(dialogClose).click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId(verifiedProofs)
|
||||
.and('contain', '1');
|
||||
});
|
||||
|
||||
it('settlement asset displayed', () => {
|
||||
// 6002-MDET-206
|
||||
cy.getByTestId(marketTitle).contains('Settlement asset').click();
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
|
||||
@@ -112,9 +130,12 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
);
|
||||
validateMarketDataRow(8, 'Withdrawal threshold', '0.0005');
|
||||
validateMarketDataRow(9, 'Lifetime limit', '1,230');
|
||||
validateMarketDataRow(10, 'Infrastructure fee account balance', '0.00001');
|
||||
validateMarketDataRow(11, 'Global reward pool account balance', '0.00002');
|
||||
});
|
||||
|
||||
it('metadata displayed', () => {
|
||||
// 6002-MDET-207
|
||||
cy.getByTestId(marketTitle).contains('Metadata').click();
|
||||
|
||||
validateMarketDataRow(0, 'Formerly', '076BB86A5AA41E3E');
|
||||
@@ -125,18 +146,21 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('risk model displayed', () => {
|
||||
// 6002-MDET-208
|
||||
cy.getByTestId(marketTitle).contains('Risk model').click();
|
||||
validateMarketDataRow(0, 'Tau', '0.0001140771161');
|
||||
validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01');
|
||||
});
|
||||
|
||||
it('risk parameters displayed', () => {
|
||||
// 6002-MDET-209
|
||||
cy.getByTestId(marketTitle).contains('Risk parameters').click();
|
||||
validateMarketDataRow(0, 'R', '0.016');
|
||||
validateMarketDataRow(1, 'Sigma', '0.3');
|
||||
});
|
||||
|
||||
it('risk factors displayed', () => {
|
||||
// 6002-MDET-210
|
||||
cy.getByTestId(marketTitle).contains('Risk factors').click();
|
||||
|
||||
validateMarketDataRow(0, 'Short', '0.008571790367285281');
|
||||
@@ -144,6 +168,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('price monitoring bounds displayed', () => {
|
||||
// 6002-MDET-211
|
||||
cy.getByTestId(marketTitle).contains('Price monitoring bounds 1').click();
|
||||
cy.get('p.col-span-1').contains('99.99999% probability price bounds');
|
||||
cy.get('p.col-span-1').contains('Within 43,200 seconds');
|
||||
@@ -152,16 +177,18 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('liquidity monitoring parameters displayed', () => {
|
||||
// 6002-MDET-212
|
||||
cy.getByTestId(marketTitle)
|
||||
.contains('Liquidity monitoring parameters')
|
||||
.click();
|
||||
|
||||
validateMarketDataRow(0, 'Triggering Ratio', '0');
|
||||
validateMarketDataRow(0, 'Triggering Ratio', '0.7');
|
||||
validateMarketDataRow(1, 'Time Window', '3,600');
|
||||
validateMarketDataRow(2, 'Scaling Factor', '10');
|
||||
});
|
||||
|
||||
it('liquidity displayed', () => {
|
||||
// 6002-MDET-213
|
||||
cy.getByTestId(marketTitle)
|
||||
.contains(/Liquidity(?! m)/)
|
||||
.click();
|
||||
@@ -169,14 +196,14 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(0, 'Target Stake', '10.00 tBTC');
|
||||
validateMarketDataRow(1, 'Supplied Stake', '0.01 tBTC');
|
||||
validateMarketDataRow(2, 'Market Value Proxy', '20.00 tBTC');
|
||||
|
||||
cy.getByTestId('view-liquidity-link').should(
|
||||
cy.getByTestId(liquidityLink).should(
|
||||
'have.text',
|
||||
'View liquidity provision table'
|
||||
);
|
||||
});
|
||||
|
||||
it('liquidity price range displayed', () => {
|
||||
// 6002-MDET-214
|
||||
cy.getByTestId(marketTitle).contains('Liquidity price range').click();
|
||||
|
||||
validateMarketDataRow(0, 'Liquidity Price Range', '2.00% of mid price');
|
||||
@@ -184,29 +211,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
validateMarketDataRow(2, 'Highest Price', '47,049.438 BTC');
|
||||
});
|
||||
|
||||
it('oracle displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Oracle').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId(providerName)
|
||||
.and('contain', 'Another oracle');
|
||||
|
||||
cy.getByTestId(providerName).should('be.visible').click();
|
||||
|
||||
cy.getByTestId('dialog-content')
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTestId('block-explorer-link').contains('Block explorer');
|
||||
cy.getByTestId('github-link').contains('Oracle repository');
|
||||
});
|
||||
cy.getByTestId('dialog-close').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.getByTestId('verified-proofs')
|
||||
.and('contain', '1');
|
||||
});
|
||||
|
||||
it('proposal displayed', () => {
|
||||
// 6002-MDET-301
|
||||
cy.getByTestId(marketTitle).contains('Proposal').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
import { checkSorting } from '@vegaprotocol/cypress';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const liquidityTab = 'Liquidity';
|
||||
const rowSelector =
|
||||
'[data-testid="tab-liquidity"] .ag-center-cols-container .ag-row';
|
||||
const rowSelectorLiquidityActive =
|
||||
'[data-testid="tab-active"] .ag-center-cols-container .ag-row';
|
||||
const rowSelectorLiquidityInactive =
|
||||
'[data-testid="tab-inactive"] .ag-center-cols-container .ag-row';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const itemValue = 'item-value';
|
||||
const itemHeader = 'item-header';
|
||||
const colCommitmentAmount = '[col-id="commitmentAmount"]';
|
||||
const colAverageEntryValuation = '[col-id="averageEntryValuation"]';
|
||||
const colEquityLikeShare = '[col-id="equityLikeShare"]';
|
||||
const colFee = '[col-id="fee"]';
|
||||
const colCommitmentAmount_1 = '[col-id="commitmentAmount_1"]';
|
||||
const colBalance = '[col-id="balance"]';
|
||||
const colStatus = '[col-id="status"]';
|
||||
const colCreatedAt = '[col-id="createdAt"] button';
|
||||
const colUpdatedAt = '[col-id="updatedAt"] button';
|
||||
|
||||
const headers = [
|
||||
'Party',
|
||||
'Commitment (tDAI)',
|
||||
'Share',
|
||||
'Proposed fee',
|
||||
'Market valuation at entry',
|
||||
'Obligation',
|
||||
'Supplied',
|
||||
'Status',
|
||||
'Created',
|
||||
'Updated',
|
||||
];
|
||||
|
||||
describe('liquidity table - trading', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockSubscription();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@MarketData');
|
||||
cy.getByTestId(liquidityTab).click();
|
||||
cy.wait('@LiquidityProvisions');
|
||||
});
|
||||
|
||||
it('can see table headers', () => {
|
||||
// 5002-LIQP-001
|
||||
cy.getByTestId('tab-liquidity').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
.each(($header, i) => {
|
||||
cy.wrap($header).should('have.text', headers[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders liquidity table correctly', () => {
|
||||
// 5002-LIQP-002
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="party.id"]')
|
||||
.should(
|
||||
'have.text',
|
||||
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
|
||||
);
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelector).first().find(colFee).should('have.text', '0.09%');
|
||||
|
||||
// 5002-LIQP-013
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colAverageEntryValuation)
|
||||
.should('have.text', '685,852.93692');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.scrollIntoView()
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelector).first().find(colStatus).should('have.text', 'Active');
|
||||
|
||||
cy.get(rowSelector).first().find(colCreatedAt).should('not.be.empty');
|
||||
cy.get(rowSelector).first().find(colUpdatedAt).should('not.be.empty');
|
||||
});
|
||||
it.skip('liquidity status column should be sorted properly', () => {
|
||||
// 5002-LIQP-003
|
||||
const liquidityColDefault = ['Active', 'Pending'];
|
||||
const liquidityColAsc = ['Active', 'Pending'];
|
||||
const liquidityColDesc = ['Pending', 'Active'];
|
||||
checkSorting(
|
||||
'status',
|
||||
liquidityColDefault,
|
||||
liquidityColAsc,
|
||||
liquidityColDesc
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockSubscription();
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
|
||||
);
|
||||
cy.visit('/#/liquidity/market-0');
|
||||
cy.wait('@LiquidityProvisions');
|
||||
});
|
||||
|
||||
it('can see header title', () => {
|
||||
// 5002-LIQP-004
|
||||
// 5002-LIQP-005
|
||||
cy.getByTestId('header-title')
|
||||
.should('contain.text', 'BTCUSD.MF21 liquidity provision')
|
||||
.and('contain.text', 'Go to trading');
|
||||
});
|
||||
|
||||
it('can see target stake', () => {
|
||||
// 5002-LIQP-006
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('target-stake').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Target stake');
|
||||
cy.getByTestId(itemValue).should('have.text', '10.00 tDAI').realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('tooltip-content').should(
|
||||
'contain.text',
|
||||
`The market's liquidity requirement which is derived from the maximum open interest observed over a rolling time window.The market's liquidity requirement which is derived from the maximum open interest observed over a rolling time window.`
|
||||
);
|
||||
});
|
||||
|
||||
it('can see supplied stake', () => {
|
||||
// 5002-LIQP-007
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('supplied-stake').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Supplied stake');
|
||||
cy.getByTestId(itemValue).should('have.text', '0.01 tDAI').realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('tooltip-content').should(
|
||||
'contain.text',
|
||||
'The current amount of liquidity supplied for this market.'
|
||||
);
|
||||
});
|
||||
|
||||
it('can see liquidity supplied', () => {
|
||||
// 5002-LIQP-008
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-supplied').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Liquidity supplied');
|
||||
cy.getByTestId('indicator').should('be.visible');
|
||||
cy.getByTestId(itemValue).should('have.text', '0.10%').realHover();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can see market id', () => {
|
||||
// 5002-LIQP-009
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-market-id').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Market ID');
|
||||
cy.getByTestId(itemValue).should('have.text', 'market-0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can see market id', () => {
|
||||
// 5002-LIQP-010
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId('liquidity-learn-more').within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Learn more');
|
||||
cy.getByTestId(itemValue).should('have.text', 'Providing liquidity');
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.attr', 'href')
|
||||
.and(
|
||||
'include',
|
||||
'https://docs.vega.xyz/testnet/concepts/liquidity/provision'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('liquidity table view', { tags: '@smoke' }, () => {
|
||||
it('can see table headers', () => {
|
||||
cy.getByTestId('tab-active').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
.each(($header, i) => {
|
||||
cy.wrap($header).should('have.text', headers[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders liquidity active table correctly', () => {
|
||||
// 5002-LIQP-011
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find('[col-id="party.id"]')
|
||||
.should(
|
||||
'have.text',
|
||||
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
|
||||
);
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colFee)
|
||||
.should('have.text', '0.09%');
|
||||
|
||||
// 5002-LIQP-013
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colAverageEntryValuation)
|
||||
.should('have.text', '685,852.93692');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colStatus)
|
||||
.should('have.text', 'Active');
|
||||
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colCreatedAt)
|
||||
.should('not.be.empty');
|
||||
cy.get(rowSelectorLiquidityActive)
|
||||
.first()
|
||||
.find(colUpdatedAt)
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('renders liquidity inactive table correctly', () => {
|
||||
// 5002-LIQP-012
|
||||
cy.getByTestId('Inactive').click();
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find('[col-id="party.id"]')
|
||||
.should(
|
||||
'have.text',
|
||||
'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
|
||||
);
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCommitmentAmount)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colEquityLikeShare)
|
||||
.should('have.text', '100.00%');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colFee)
|
||||
.should('have.text', '0.40%');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colAverageEntryValuation)
|
||||
.should('have.text', '685,852.93692');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCommitmentAmount_1)
|
||||
.should('have.text', '4,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colBalance)
|
||||
.should('have.text', '2,000.00');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colStatus)
|
||||
.should('have.text', 'Pending');
|
||||
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colCreatedAt)
|
||||
.should('not.be.empty');
|
||||
cy.get(rowSelectorLiquidityInactive)
|
||||
.first()
|
||||
.find(colUpdatedAt)
|
||||
.should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -25,6 +25,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
cy.wait('@MarketsCandles');
|
||||
});
|
||||
|
||||
// 6001-MARK-066
|
||||
it('can toggle the sidebar', () => {
|
||||
cy.getByTestId('market-selector').should('be.visible');
|
||||
cy.getByTestId('sidebar-toggle').click();
|
||||
@@ -67,6 +68,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
.each((item, i) => {
|
||||
const market = data[i];
|
||||
// 6001-MARK-021
|
||||
// 6001-MARK-022
|
||||
expect(item.find('h3').text()).equals(market.code);
|
||||
expect(
|
||||
item.find('[data-testid="market-selector-data-row"]').eq(0).text()
|
||||
@@ -84,8 +86,19 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
});
|
||||
});
|
||||
|
||||
// 6001-MARK-27
|
||||
it('can see all markets link', () => {
|
||||
// 6001-MARK-026
|
||||
cy.getByTestId('market-selector').within(() => {
|
||||
cy.getByTestId('all-markets-link')
|
||||
.should('be.visible')
|
||||
.and('have.text', 'All markets')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '#/markets/all');
|
||||
});
|
||||
});
|
||||
|
||||
it('can use the filter options', () => {
|
||||
// 6001-MARK-027
|
||||
// product type
|
||||
cy.getByTestId('product-Spot').click();
|
||||
cy.getByTestId(list).contains('Spot markets coming soon.');
|
||||
@@ -94,7 +107,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('product-Future').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
|
||||
// 6001-MARK-29
|
||||
// 6001-MARK-029
|
||||
cy.getByTestId(searchInput).clear().type('btc');
|
||||
cy.getByTestId(list).find('a').should('have.length', 2);
|
||||
cy.getByTestId(list).find('a').eq(1).contains('BTCUSD.MF21');
|
||||
@@ -103,4 +116,29 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(searchInput).clear();
|
||||
cy.getByTestId(list).find('a').should('have.length', 4);
|
||||
});
|
||||
|
||||
it('can sort by by top gaining and top losing market', () => {
|
||||
// 6001-MARK-030
|
||||
// 6001-MARK-031
|
||||
// 6001-MARK-032
|
||||
// 6001-MARK-033
|
||||
cy.getByTestId(' sort-trigger').click();
|
||||
cy.getByTestId('sort-item-Gained')
|
||||
.contains('Top gaining')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-Lost')
|
||||
.contains('Top losing')
|
||||
.should('be.visible');
|
||||
cy.getByTestId('sort-item-New')
|
||||
.contains('New markets')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('can filter by settlement asset', () => {
|
||||
// 6001-MARK-028
|
||||
cy.getByTestId('asset-trigger').click();
|
||||
cy.getByTestId('asset-id-asset-3').contains('tBTC').click();
|
||||
cy.getByTestId(list).find('a').should('have.length', 1);
|
||||
cy.getByTestId(list).find('a').eq(0).contains('ETHBTC.QM21');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const marketExpiry = 'market-expiry';
|
||||
const marketPrice = 'market-price';
|
||||
const marketChange = 'market-change';
|
||||
const marketVolume = 'market-volume';
|
||||
const marketMode = 'market-trading-mode';
|
||||
const marketState = 'market-state';
|
||||
const marketSettlement = 'market-settlement-asset';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
const priceChangeValue = 'price-change';
|
||||
const expirtyTooltip = 'expiry-tooltip';
|
||||
const externalLink = 'external-link';
|
||||
const itemHeader = 'item-header';
|
||||
const itemValue = 'item-value';
|
||||
const link = 'link';
|
||||
const liquidityLink = 'view-liquidity-link';
|
||||
const liquiditySupplied = 'liquidity-supplied';
|
||||
const liquiditySuppliedTooltip = 'liquidity-supplied-tooltip';
|
||||
const marketChange = 'market-change';
|
||||
const marketExpiry = 'market-expiry';
|
||||
const marketMode = 'market-trading-mode';
|
||||
const marketName = 'header-title';
|
||||
const marketPrice = 'market-price';
|
||||
const marketSettlement = 'market-settlement-asset';
|
||||
const marketState = 'market-state';
|
||||
const marketSummaryBlock = 'header-summary';
|
||||
const marketVolume = 'market-volume';
|
||||
const percentageValue = 'price-change-percentage';
|
||||
const priceChangeValue = 'price-change';
|
||||
const tradingModeTooltip = 'trading-mode-tooltip';
|
||||
|
||||
describe('Market trading page', () => {
|
||||
before(() => {
|
||||
@@ -31,10 +39,12 @@ describe('Market trading page', () => {
|
||||
// 7002-SORD-001
|
||||
// 7002-SORD-002
|
||||
it('must display market name', () => {
|
||||
cy.getByTestId('header-title').should('not.be.empty');
|
||||
// 6002-MDET-001
|
||||
cy.getByTestId(marketName).should('not.be.empty');
|
||||
});
|
||||
|
||||
it('must see market expiry', () => {
|
||||
// 6002-MDET-002
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketExpiry).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Expiry');
|
||||
@@ -44,6 +54,7 @@ describe('Market trading page', () => {
|
||||
});
|
||||
|
||||
it('must see market price', () => {
|
||||
// 6002-MDET-003
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketPrice).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Price');
|
||||
@@ -53,6 +64,7 @@ describe('Market trading page', () => {
|
||||
});
|
||||
|
||||
it('must see market change', () => {
|
||||
// 6002-MDET-004
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketChange).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Change (24h)');
|
||||
@@ -63,6 +75,7 @@ describe('Market trading page', () => {
|
||||
});
|
||||
|
||||
it('must see market volume', () => {
|
||||
// 6002-MDET-005
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketVolume).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Volume (24h)');
|
||||
@@ -72,16 +85,21 @@ describe('Market trading page', () => {
|
||||
});
|
||||
|
||||
it('must see market mode', () => {
|
||||
// 6002-MDET-006
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketMode).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Trading mode');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
cy.getByTestId(itemValue).should(
|
||||
'have.text',
|
||||
'Monitoring auction - liquidity (target not met)'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market state', () => {
|
||||
//7002-SORD-061
|
||||
it('must see market status', () => {
|
||||
// 6002-MDET-007
|
||||
// 7002-SORD-061
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketState).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Status');
|
||||
@@ -91,6 +109,7 @@ describe('Market trading page', () => {
|
||||
});
|
||||
|
||||
it('must see market settlement', () => {
|
||||
// 6002-MDET-008
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketSettlement).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Settlement asset');
|
||||
@@ -98,15 +117,12 @@ describe('Market trading page', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('must see market mode', () => {
|
||||
it('must see market liquidity supplied', () => {
|
||||
// 6002-MDET-009
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(marketMode).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Trading mode');
|
||||
cy.getByTestId(itemValue).should(
|
||||
'have.text',
|
||||
'Monitoring auction - liquidity (target not met)'
|
||||
);
|
||||
cy.getByTestId(liquiditySupplied).within(() => {
|
||||
cy.getByTestId(itemHeader).should('have.text', 'Liquidity supplied');
|
||||
cy.getByTestId(itemValue).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -121,14 +137,14 @@ describe('Market trading page', () => {
|
||||
.realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId('expiry-tooltip')
|
||||
cy.getByTestId(expirtyTooltip)
|
||||
.eq(0)
|
||||
.should(
|
||||
'contain.text',
|
||||
'This market expires when triggered by its oracle, not on a set date.'
|
||||
)
|
||||
.within(() => {
|
||||
cy.getByTestId('link')
|
||||
cy.getByTestId(link)
|
||||
.should('have.attr', 'href')
|
||||
.and('include', Cypress.env('EXPLORER_URL'));
|
||||
});
|
||||
@@ -154,15 +170,14 @@ describe('Market trading page', () => {
|
||||
.realHover();
|
||||
});
|
||||
});
|
||||
|
||||
cy.getByTestId('trading-mode-tooltip')
|
||||
cy.getByTestId(tradingModeTooltip)
|
||||
.should(
|
||||
'contain.text',
|
||||
'This market is in auction until it reaches sufficient liquidity.'
|
||||
)
|
||||
.eq(0)
|
||||
.within(() => {
|
||||
cy.getByTestId('external-link')
|
||||
cy.getByTestId(externalLink)
|
||||
.should('have.attr', 'href')
|
||||
.and('include', Cypress.env('TRADING_MODE_LINK'));
|
||||
|
||||
@@ -174,5 +189,27 @@ describe('Market trading page', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should see liquidity supplied tooltip', () => {
|
||||
cy.getByTestId(marketSummaryBlock).within(() => {
|
||||
cy.getByTestId(liquiditySupplied).within(() => {
|
||||
cy.getByTestId(itemValue).realHover();
|
||||
});
|
||||
});
|
||||
cy.getByTestId(liquiditySuppliedTooltip)
|
||||
.should('contain.text', 'Supplied stake')
|
||||
.and('contain.text', 'Target stake')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getByTestId(liquidityLink).should(
|
||||
'have.text',
|
||||
'View liquidity provision table'
|
||||
);
|
||||
cy.getByTestId(externalLink).should(
|
||||
'have.text',
|
||||
'Learn about providing liquidity'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { checkSorting } from '@vegaprotocol/cypress';
|
||||
import { aliasGQLQuery, checkSorting } from '@vegaprotocol/cypress';
|
||||
import type { ProposalsListQuery } from '@vegaprotocol/proposals';
|
||||
|
||||
const rowSelector =
|
||||
'[data-testid="tab-proposed-markets"] .ag-center-cols-container .ag-row';
|
||||
const colMarketId = '[col-id="market"]';
|
||||
|
||||
describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage().then(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
});
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
});
|
||||
|
||||
it('can see table headers', () => {
|
||||
@@ -35,10 +35,7 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
|
||||
it('renders markets correctly', () => {
|
||||
// 6001-MARK-049
|
||||
cy.get(rowSelector)
|
||||
.first()
|
||||
.find('[col-id="market"]')
|
||||
.should('have.text', 'ETHUSD');
|
||||
cy.get(rowSelector).first().find(colMarketId).should('have.text', 'ETHUSD');
|
||||
|
||||
// 6001-MARK-050
|
||||
cy.get(rowSelector)
|
||||
@@ -119,6 +116,7 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
);
|
||||
});
|
||||
it('proposed markets tab should be sorted properly', () => {
|
||||
// 6001-MARK-062
|
||||
cy.get('[data-testid="Proposed markets"]').click({ force: true });
|
||||
const marketColDefault = [
|
||||
'ETHUSD',
|
||||
@@ -196,4 +194,31 @@ describe('markets proposed table', { tags: '@smoke' }, () => {
|
||||
];
|
||||
checkSorting('state', stateColDefault, stateColAsc, stateColDesc);
|
||||
});
|
||||
|
||||
it('can drag and drop columns', () => {
|
||||
// 6001-MARK-063
|
||||
cy.get(colMarketId).realMouseDown().realMouseMove(700, 15).realMouseUp();
|
||||
cy.get(colMarketId).should(($element) => {
|
||||
const attributeValue = $element.attr('aria-colindex');
|
||||
expect(attributeValue).not.to.equal('1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('no markets proposed', { tags: '@smoke', testIsolation: true }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
const proposal: ProposalsListQuery = {};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'ProposalsList', proposal);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/all');
|
||||
cy.get('[data-testid="Proposed markets"]').click();
|
||||
});
|
||||
|
||||
it('can see no markets message', () => {
|
||||
// 6001-MARK-061
|
||||
cy.getByTestId('tab-proposed-markets').should('contain.text', 'No markets');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
|
||||
const oracleBannerDialogTrigger = 'oracle-banner-dialog-trigger';
|
||||
const oracleBannerStatus = 'oracle-banner-status';
|
||||
const oracleFullProfile = 'oracle-full-profile';
|
||||
|
||||
describe('oracle information', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage(
|
||||
MarketState.STATE_ACTIVE,
|
||||
undefined,
|
||||
undefined,
|
||||
'COMPROMISED'
|
||||
);
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
it('show oracle banner', () => {
|
||||
cy.getByTestId(oracleBannerStatus).should('contain.text', 'COMPROMISED');
|
||||
cy.getByTestId(oracleBannerDialogTrigger)
|
||||
.should('contain.text', 'Show more')
|
||||
.click();
|
||||
cy.getByTestId(oracleFullProfile).should('exist');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
const orderbookTab = 'Orderbook';
|
||||
const orderbookTable = 'tab-orderbook';
|
||||
const askPrice = 'price-9894585';
|
||||
const bidPrice = 'price-9889001';
|
||||
const askVolume = 'ask-vol-9894585';
|
||||
const bidVolume = 'bid-vol-9889001';
|
||||
const askCumulative = 'cumulative-vol-9894585';
|
||||
const bidCumulative = 'cumulative-vol-9889001';
|
||||
const midPrice = 'middle-mark-price-4612690000';
|
||||
const priceResolution = 'resolution';
|
||||
const dealTicketPrice = 'order-price';
|
||||
const resPrice = 'price-990';
|
||||
|
||||
describe('order book', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
});
|
||||
|
||||
it('show order book', () => {
|
||||
// 6003-ORDB-001
|
||||
// 6003-ORDB-002
|
||||
cy.getByTestId(orderbookTab).click();
|
||||
cy.getByTestId(orderbookTable).should('be.visible');
|
||||
cy.getByTestId(orderbookTable).should('not.be.empty');
|
||||
});
|
||||
|
||||
it('show orders prices', () => {
|
||||
// 6003-ORDB-003
|
||||
cy.getByTestId(askPrice).should('have.text', '98.94585');
|
||||
cy.getByTestId(bidPrice).should('have.text', '98.89001');
|
||||
});
|
||||
|
||||
it('show prices volumes', () => {
|
||||
// 6003-ORDB-004
|
||||
cy.getByTestId(askVolume).should('have.text', '1');
|
||||
cy.getByTestId(bidVolume).should('have.text', '1');
|
||||
});
|
||||
|
||||
it('show prices cumulative volumes', () => {
|
||||
// 6003-ORDB-005
|
||||
cy.getByTestId(askCumulative).should('have.text', '39');
|
||||
cy.getByTestId(bidCumulative).should('have.text', '7');
|
||||
});
|
||||
|
||||
it('show mid price', () => {
|
||||
// 6003-ORDB-006
|
||||
cy.getByTestId(midPrice).should('have.text', '46,126.90');
|
||||
});
|
||||
|
||||
it('sort prices descending', () => {
|
||||
// 6003-ORDB-007
|
||||
const prices: number[] = [];
|
||||
cy.getByTestId(orderbookTable).within(() => {
|
||||
cy.get('[data-testid*=price]')
|
||||
.each(($el) => {
|
||||
prices.push(Number($el.text()));
|
||||
})
|
||||
.then(() => {
|
||||
expect(prices).to.deep.equal(prices.sort((a, b) => b - a));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('copy price to deal ticket form', () => {
|
||||
// 6003-ORDB-009
|
||||
cy.getByTestId(askPrice).click();
|
||||
cy.getByTestId(dealTicketPrice).should('have.value', '98.94585');
|
||||
});
|
||||
|
||||
it('change price resolution', () => {
|
||||
// 6003-ORDB-008
|
||||
const resolutions = [
|
||||
'0.00000',
|
||||
'0.0000',
|
||||
'0.000',
|
||||
'0.00',
|
||||
'0.0',
|
||||
'0',
|
||||
'10',
|
||||
'100',
|
||||
'1,000',
|
||||
'10,000',
|
||||
];
|
||||
cy.getByTestId(priceResolution)
|
||||
.find('option')
|
||||
.each(($el, index) => {
|
||||
expect($el.text()).to.equal(resolutions[index]);
|
||||
});
|
||||
|
||||
cy.getByTestId(priceResolution).select('0.0');
|
||||
cy.getByTestId(resPrice).should('have.text', '99.0');
|
||||
cy.getByTestId(askPrice).should('not.exist');
|
||||
cy.getByTestId(bidPrice).should('not.exist');
|
||||
});
|
||||
});
|
||||
@@ -20,6 +20,7 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
// 7001-COLL-006
|
||||
// 7001-COLL-007
|
||||
// 1003-TRAN-001
|
||||
// 7001-COLL-012
|
||||
|
||||
const tradingAccountRowId = '[row-id="t-0"]';
|
||||
cy.getByTestId('Collateral').click();
|
||||
@@ -34,28 +35,23 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="used"]')
|
||||
.should('have.text', '1.010.00%');
|
||||
.should('have.text', '1.01' + '1.00%');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="available"]')
|
||||
.should('have.text', '100,000.00');
|
||||
.should('have.text', '100.00');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="total"]')
|
||||
.should('have.text', '100,001.01');
|
||||
.should('have.text', '101.01');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="accounts-actions"]')
|
||||
.should('have.text', '');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="total"]')
|
||||
.should('have.text', '100,001.01');
|
||||
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get('[col-id="accounts-actions"]')
|
||||
.find('[data-testid="dropdown-menu"]')
|
||||
@@ -101,7 +97,7 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
'Liquidity provision fee reward account balance',
|
||||
'Market proposer reward account balance',
|
||||
];
|
||||
cy.getByTestId('asset').contains('tEURO').click();
|
||||
cy.get('[col-id="asset.symbol"]').contains('tEURO').click();
|
||||
cy.get('[data-testid$="_label"]').should('have.length', 16);
|
||||
cy.get('[data-testid$="_label"]').each((element, index) => {
|
||||
cy.wrap(element).should('have.text', titles[index]);
|
||||
@@ -112,8 +108,8 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
|
||||
it('should open usage breakdown dialog when clicked on used', () => {
|
||||
// 7001-COLL-009
|
||||
cy.getByTestId('breakdown').contains('1.01').click();
|
||||
const headers = ['Market', 'Account type', 'Balance'];
|
||||
cy.get('[col-id="used"]').contains('1.01').click();
|
||||
const headers = ['Market', 'Account type', 'Balance', 'Margin health'];
|
||||
cy.getByTestId('usage-breakdown').within(($headers) => {
|
||||
cy.wrap($headers)
|
||||
.get('.ag-header-cell-text')
|
||||
@@ -132,12 +128,14 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
cy.wrap(btn).click();
|
||||
});
|
||||
}
|
||||
cy.contains('Loading...').should('not.exist');
|
||||
});
|
||||
// 7001-COLL-010
|
||||
it('sorting by asset', () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
const marketsSortedDefault = ['tBTC', 'tEURO', 'tDAI', 'tBTC'];
|
||||
const marketsSortedAsc = ['tBTC', 'tBTC', 'tDAI', 'tEURO'];
|
||||
const marketsSortedDesc = ['tEURO', 'tDAI', 'tBTC', 'tBTC'];
|
||||
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
|
||||
checkSorting(
|
||||
'asset.symbol',
|
||||
marketsSortedDefault,
|
||||
@@ -160,12 +158,8 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
'1,000.00002',
|
||||
'1,000.01',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'1,000.01',
|
||||
'1,000.00002',
|
||||
'1,000.00001',
|
||||
'1,000.00',
|
||||
];
|
||||
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
|
||||
|
||||
checkSorting(
|
||||
'total',
|
||||
marketsSortedDefault,
|
||||
@@ -176,24 +170,22 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
|
||||
it('sorting by used', () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
// concat actual value with percentage value
|
||||
// as cypress will pick up the entire cell contes
|
||||
// textContent
|
||||
const marketsSortedDefault = [
|
||||
'0.000.00%',
|
||||
'0.010.00%',
|
||||
'0.000.00%',
|
||||
'0.000.00%',
|
||||
'0.00' + '0.00%',
|
||||
'0.01' + '0.00%',
|
||||
'0.00' + '0.00%',
|
||||
'0.00' + '0.00%',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'0.000.00%',
|
||||
'0.000.00%',
|
||||
'0.000.00%',
|
||||
'0.010.00%',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'0.010.00%',
|
||||
'0.000.00%',
|
||||
'0.000.00%',
|
||||
'0.000.00%',
|
||||
'0.00' + '0.00%',
|
||||
'0.00' + '0.00%',
|
||||
'0.00' + '0.00%',
|
||||
'0.01' + '0.00%',
|
||||
];
|
||||
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
|
||||
checkSorting(
|
||||
'used',
|
||||
marketsSortedDefault,
|
||||
@@ -202,29 +194,24 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('sorting by total', () => {
|
||||
it('sorting by available', () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
const marketsSortedDefault = [
|
||||
'1,000.00002',
|
||||
'1,000.01',
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
'1,000.00002',
|
||||
'1,000.01',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'1,000.01',
|
||||
'1,000.00002',
|
||||
'1,000.00001',
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
'1,000.00002',
|
||||
];
|
||||
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
|
||||
|
||||
checkSorting(
|
||||
'total',
|
||||
'available',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
|
||||
@@ -81,14 +81,15 @@ describe(
|
||||
cy.visit('/#/markets/market-0');
|
||||
});
|
||||
it('must display that market is not accepting orders', function () {
|
||||
cy.getByTestId('dealticket-error-message-summary').should(
|
||||
cy.getByTestId('deal-ticket-error-message-summary').should(
|
||||
'have.text',
|
||||
`This market is ${marketState
|
||||
.split('_')
|
||||
.pop()
|
||||
?.toLowerCase()} and not accepting orders`
|
||||
);
|
||||
cy.getByTestId('place-order').should('be.disabled');
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId('place-order').should('be.enabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
|
||||
cy.getByTestId('dealticket-error-message-expiry').should(
|
||||
cy.getByTestId('deal-ticket-error-message-expiry').should(
|
||||
'have.text',
|
||||
'The expiry date that you have entered appears to be in the past'
|
||||
);
|
||||
@@ -57,7 +57,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(orderTIFDropDown).select('TIME_IN_FORCE_GTC');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(orderPriceField).clear().type('1.123456');
|
||||
cy.getByTestId('dealticket-error-message-price-limit').should(
|
||||
cy.getByTestId('deal-ticket-error-message-price-limit').should(
|
||||
'have.text',
|
||||
'Price accepts up to 5 decimal places'
|
||||
);
|
||||
@@ -77,8 +77,9 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
it('must warn if order size input has too many digits after the decimal place', function () {
|
||||
// 7002-SORD-016
|
||||
cy.getByTestId(orderSizeField).clear().type('1.234');
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('deal-ticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size must be whole numbers for this market'
|
||||
);
|
||||
@@ -86,23 +87,38 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
|
||||
|
||||
it('must warn if order size is set to 0', function () {
|
||||
cy.getByTestId(orderSizeField).clear().type('0');
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-size-market').should(
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('deal-ticket-error-message-size-market').should(
|
||||
'have.text',
|
||||
'Size cannot be lower than 1'
|
||||
);
|
||||
});
|
||||
|
||||
it('must have total margin available', () => {
|
||||
// 7001-COLL-011
|
||||
cy.getByTestId('tab-ticket')
|
||||
.find('.text-xs')
|
||||
.eq(5)
|
||||
.within(() => {
|
||||
cy.get('[data-state="closed"]').should(
|
||||
'have.text',
|
||||
'Total margin available100,000.01 tDAI'
|
||||
);
|
||||
});
|
||||
cy.getByTestId('deal-ticket-fee-total-margin-available').within(() => {
|
||||
cy.get('[data-state="closed"]').should(
|
||||
'have.text',
|
||||
'Total margin available100.01 tDAI'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('must have current margin allocation', () => {
|
||||
cy.getByTestId('deal-ticket-fee-current-margin-allocation').within(() => {
|
||||
cy.get('[data-state="closed"]:first').should(
|
||||
'have.text',
|
||||
'Current margin allocation'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should open usage breakdown dialog when clicked on current margin allocation', () => {
|
||||
cy.getByTestId('deal-ticket-fee-current-margin-allocation').within(() => {
|
||||
cy.get('button').click();
|
||||
});
|
||||
cy.getByTestId('usage-breakdown').should('exist');
|
||||
cy.getByTestId('dialog-close').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { accountsQuery, amendGeneralAccountBalance } from '@vegaprotocol/mock';
|
||||
import {
|
||||
accountsQuery,
|
||||
amendGeneralAccountBalance,
|
||||
amendMarginAccountBalance,
|
||||
} from '@vegaprotocol/mock';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
@@ -12,8 +16,9 @@ describe(
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
const accounts = accountsQuery();
|
||||
amendGeneralAccountBalance(accounts, 'market-0', '0');
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
@@ -23,13 +28,19 @@ describe(
|
||||
});
|
||||
|
||||
it('should show an error if your balance is zero', () => {
|
||||
cy.getByTestId('place-order').should('be.disabled');
|
||||
const accounts = accountsQuery();
|
||||
amendMarginAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId('place-order').should('be.enabled');
|
||||
// 7002-SORD-003
|
||||
cy.getByTestId('dealticket-error-message-zero-balance').should(
|
||||
cy.getByTestId('deal-ticket-error-message-zero-balance').should(
|
||||
'have.text',
|
||||
'You need ' +
|
||||
'tDAI' +
|
||||
' in your wallet to trade in this market.See all your collateral.Make a deposit'
|
||||
' in your wallet to trade in this market. See all your collateral.Make a deposit'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
|
||||
});
|
||||
@@ -39,8 +50,9 @@ describe(
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
const accounts = accountsQuery();
|
||||
amendGeneralAccountBalance(accounts, 'market-0', '1');
|
||||
let accounts = accountsQuery();
|
||||
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
|
||||
accounts = amendGeneralAccountBalance(accounts, 'market-0', '1');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
@@ -53,11 +65,11 @@ describe(
|
||||
// 7002-SORD-003
|
||||
|
||||
// warning should show immediately
|
||||
cy.getByTestId('dealticket-warning-margin').should(
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position'
|
||||
);
|
||||
cy.getByTestId('dealticket-warning-margin').should(
|
||||
cy.getByTestId('deal-ticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'You may not have enough margin available to open this position. 5.00 tDAI is currently required. You have only 0.01001 tDAI available.'
|
||||
);
|
||||
|
||||
@@ -34,10 +34,10 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
|
||||
it('should show warning for market order', function () {
|
||||
cy.getByTestId(toggleMarket).click();
|
||||
cy.getByTestId(placeOrderBtn).should('not.be.disabled');
|
||||
// 7002-SORD-060
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId(placeOrderBtn).click();
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-type').should(
|
||||
cy.getByTestId('deal-ticket-error-message-type').should(
|
||||
'have.text',
|
||||
'This market is in auction until it reaches sufficient liquidity. Only limit orders are permitted when market is in auction'
|
||||
);
|
||||
@@ -48,7 +48,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
cy.getByTestId(orderPriceField).clear().type('0.1');
|
||||
cy.getByTestId(orderSizeField).clear().type('1');
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('dealticket-warning-auction').should(
|
||||
cy.getByTestId('deal-ticket-warning-auction').should(
|
||||
'have.text',
|
||||
'Any orders placed now will not trade until the auction ends'
|
||||
);
|
||||
@@ -59,8 +59,8 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
cy.getByTestId(orderTIFDropDown).select(
|
||||
TIFlist.filter((item) => item.code === 'FOK')[0].value
|
||||
);
|
||||
cy.getByTestId(placeOrderBtn).should('be.disabled');
|
||||
cy.getByTestId('dealticket-error-message-tif').should(
|
||||
cy.getByTestId(placeOrderBtn).should('be.enabled');
|
||||
cy.getByTestId('deal-ticket-error-message-tif').should(
|
||||
'have.text',
|
||||
'This market is in auction until it reaches sufficient liquidity. Until the auction ends, you can only place GFA, GTT, or GTC limit orders'
|
||||
);
|
||||
|
||||
@@ -5,6 +5,10 @@ import {
|
||||
toggleMarket,
|
||||
} from '../support/deal-ticket';
|
||||
|
||||
const tooltipContent = 'tooltip-content';
|
||||
const reduceOnly = 'reduce-only';
|
||||
const postOnly = 'post-only';
|
||||
|
||||
describe('time in force validation', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
cy.setVegaWallet();
|
||||
@@ -122,13 +126,18 @@ describe('time in force validation', { tags: '@smoke' }, () => {
|
||||
// 7002-SORD-026
|
||||
|
||||
it(`post and reduce order market for ${tif.code}`, function () {
|
||||
// 7003-SORD-054
|
||||
// 7003-SORD-055
|
||||
// 7003-SORD-056
|
||||
// 7003-SORD-057
|
||||
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
cy.getByTestId('post-only').should('be.disabled');
|
||||
cy.getByTestId('reduce-only').should('be.enabled');
|
||||
cy.getByTestId(postOnly).should('be.disabled');
|
||||
cy.getByTestId(reduceOnly).should('be.enabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -144,14 +153,33 @@ describe('time in force validation', { tags: '@smoke' }, () => {
|
||||
|
||||
validTIFLimit.forEach((tif) => {
|
||||
it(`post and reduce order for limit ${tif.code}`, function () {
|
||||
// 7003-SORD-054
|
||||
// 7003-SORD-055
|
||||
// 7003-SORD-056
|
||||
// 7003-SORD-057
|
||||
cy.getByTestId(orderTIFDropDown).select(tif.value);
|
||||
cy.get(`[data-testid=${orderTIFDropDown}] option:selected`).should(
|
||||
'have.text',
|
||||
tif.text
|
||||
);
|
||||
cy.getByTestId('post-only').should('be.enabled');
|
||||
cy.getByTestId('reduce-only').should('be.disabled');
|
||||
cy.getByTestId(postOnly).should('be.enabled');
|
||||
cy.getByTestId(reduceOnly).should('be.disabled');
|
||||
});
|
||||
});
|
||||
it(`can see explanation of what post only and reduce only is/does`, function () {
|
||||
// 7003-SORD-058
|
||||
cy.get('[for="post-only"]').should('have.text', 'Post only').realHover();
|
||||
cy.getByTestId(tooltipContent).should(
|
||||
'contain.text',
|
||||
`"Post only" will ensure the order is not filled immediately but is placed on the order book as a passive order. When the order is processed it is either stopped (if it would not be filled immediately), or placed in the order book as a passive order until the price taker matches with it.`
|
||||
);
|
||||
cy.get('[for="reduce-only"]')
|
||||
.should('have.text', 'Reduce only')
|
||||
.realHover();
|
||||
cy.getByTestId(tooltipContent).should(
|
||||
'contain.text',
|
||||
`"Reduce only" can be used only with non-persistent orders, such as "Fill or Kill" or "Immediate or Cancel".`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
import { checkSorting } from '@vegaprotocol/cypress';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { checkSorting, aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketsDataQuery } from '@vegaprotocol/mock';
|
||||
import { positionsQuery } from '@vegaprotocol/mock';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
// #region consts
|
||||
const closePosition = 'close-position';
|
||||
const dialogCloseX = 'dialog-close';
|
||||
const dialogContent = 'dialog-content';
|
||||
const dropDownMenu = 'dropdown-menu';
|
||||
const marketActionsContent = 'market-actions-content';
|
||||
const positions = 'Positions';
|
||||
const tabPositions = 'tab-positions';
|
||||
const toastContent = 'toast-content';
|
||||
const tooltipContent = 'tooltip-content';
|
||||
// #endregion
|
||||
|
||||
describe('positions', { tags: '@smoke', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
it('renders positions on trading page', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Positions').click();
|
||||
visitAndClickPositions();
|
||||
// 7004-POSI-001
|
||||
// 7004-POSI-002
|
||||
validatePositionsDisplayed();
|
||||
});
|
||||
|
||||
@@ -35,174 +46,321 @@ describe('positions', { tags: '@smoke', testIsolation: true }, () => {
|
||||
}
|
||||
aliasGQLQuery(req, 'Positions', positions);
|
||||
});
|
||||
cy.visit('/#/portfolio');
|
||||
cy.getByTestId('Positions').click();
|
||||
visitAndClickPositions();
|
||||
// 7004-POSI-001
|
||||
// 7004-POSI-002
|
||||
validatePositionsDisplayed(true);
|
||||
});
|
||||
describe('renders position among some graphql errors', () => {
|
||||
it('rows should be displayed despite errors', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for market: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['marketsConnection', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
|
||||
it('Close my position', () => {
|
||||
visitAndClickPositions();
|
||||
cy.getByTestId(closePosition).first().click();
|
||||
// 7004-POSI-010
|
||||
cy.getByTestId(toastContent).should(
|
||||
'contain.text',
|
||||
'Awaiting confirmation'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('positions', { tags: '@regression', testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('rows should be displayed despite errors', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for market: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['marketsConnection', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
];
|
||||
const marketData = marketsDataQuery();
|
||||
const edges = marketData.marketsConnection?.edges.map((market) => {
|
||||
const replace =
|
||||
market.node.data?.market.id === 'market-2' ? null : market.node.data;
|
||||
return { ...market, node: { ...market.node, data: replace } };
|
||||
});
|
||||
const overrides = {
|
||||
...marketData,
|
||||
marketsConnection: { ...marketData.marketsConnection, edges },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
const emptyCells = [
|
||||
'notional',
|
||||
'markPrice',
|
||||
'currentLeverage',
|
||||
'averageEntryPrice',
|
||||
];
|
||||
cy.getByTestId('tab-positions')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(
|
||||
'[row-id="02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65-market-2"]'
|
||||
)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
emptyCells.forEach((cell) => {
|
||||
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
|
||||
});
|
||||
},
|
||||
];
|
||||
const marketData = marketsDataQuery();
|
||||
const edges = marketData.marketsConnection?.edges.map((market) => {
|
||||
const replace =
|
||||
market.node.data?.market.id === 'market-2' ? null : market.node.data;
|
||||
return { ...market, node: { ...market.node, data: replace } };
|
||||
});
|
||||
const overrides = {
|
||||
...marketData,
|
||||
marketsConnection: { ...marketData.marketsConnection, edges },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
const emptyCells = [
|
||||
'notional',
|
||||
'markPrice',
|
||||
'currentLeverage',
|
||||
'averageEntryPrice',
|
||||
];
|
||||
cy.getByTestId(tabPositions)
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get(
|
||||
'[row-id="02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65-market-2"]'
|
||||
)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
emptyCells.forEach((cell) => {
|
||||
cy.get(`[col-id="${cell}"]`).should('contain.text', '-');
|
||||
});
|
||||
});
|
||||
});
|
||||
it('error message should be displayed', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for asset: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['assets', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
},
|
||||
];
|
||||
const overrides = {
|
||||
marketsConnection: { edges: [] },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.get('[data-testid="tab-positions"]').contains('no market data');
|
||||
});
|
||||
|
||||
it('error message should be displayed', () => {
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'no market data for asset: 9c55fb644c6f7de5422d40d691a62bffd5898384c70135bab29ba1e3e2e5280a',
|
||||
path: ['assets', 'edges'],
|
||||
extensions: {
|
||||
code: 13,
|
||||
type: 'Internal',
|
||||
},
|
||||
},
|
||||
];
|
||||
const overrides = {
|
||||
marketsConnection: { edges: [] },
|
||||
};
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'MarketsData', overrides, errors);
|
||||
});
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(tabPositions).contains('no market data');
|
||||
});
|
||||
|
||||
it('sorting by Market', () => {
|
||||
visitAndClickPositions();
|
||||
const marketsSortedDefault = [
|
||||
'ACTIVE MARKET',
|
||||
'Apple Monthly (30 Jun 2022)',
|
||||
'ETHBTC Quarterly (30 Jun 2022)',
|
||||
'SUSPENDED MARKET',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'ACTIVE MARKET',
|
||||
'Apple Monthly (30 Jun 2022)',
|
||||
'ETHBTC Quarterly (30 Jun 2022)',
|
||||
'SUSPENDED MARKET',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'SUSPENDED MARKET',
|
||||
'ETHBTC Quarterly (30 Jun 2022)',
|
||||
'Apple Monthly (30 Jun 2022)',
|
||||
'ACTIVE MARKET',
|
||||
];
|
||||
cy.getByTestId(positions).click();
|
||||
// 7004-POSI-003
|
||||
checkSorting(
|
||||
'marketName',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
);
|
||||
});
|
||||
|
||||
// let elementWidth: number;
|
||||
|
||||
it('Resize column', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('.ag-overlay-loading-wrapper').should('not.be.visible');
|
||||
cy.get('.ag-header-container').within(() => {
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.find('.ag-header-cell-resize')
|
||||
.realMouseDown()
|
||||
.realMouseMove(250, 0)
|
||||
.realMouseUp();
|
||||
});
|
||||
|
||||
// 7004-POSI-006
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.invoke('width')
|
||||
.should('be.greaterThan', 250);
|
||||
});
|
||||
|
||||
// This test depends on the previous one
|
||||
it('Has persisted column widths', () => {
|
||||
const width = 400;
|
||||
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem(
|
||||
'vega_positions_store',
|
||||
JSON.stringify({
|
||||
state: {
|
||||
gridStore: {
|
||||
columnState: [{ colId: 'marketName', width }],
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
visitAndClickPositions();
|
||||
|
||||
// 7004-POSI-012
|
||||
cy.get('.ag-center-cols-container .ag-row')
|
||||
.first()
|
||||
.find('[col-id="marketName"]')
|
||||
.invoke('outerWidth')
|
||||
.should('equal', width);
|
||||
});
|
||||
|
||||
it('Scroll horizontally', () => {
|
||||
visitAndClickPositions();
|
||||
|
||||
cy.get('.ag-header-container').within(() => {
|
||||
cy.get(`[col-id="marketName"]`)
|
||||
.find('.ag-header-cell-resize')
|
||||
.realMouseDown()
|
||||
.realMouseMove(400, 0)
|
||||
.realMouseUp();
|
||||
});
|
||||
cy.get('[col-id="marketName"]').should('be.visible');
|
||||
cy.get('.ag-body-horizontal-scroll-viewport').realMouseWheel({
|
||||
deltaX: 500,
|
||||
});
|
||||
// 7004-POSI-004
|
||||
cy.get('[col-id="updatedAt"]').should('be.visible');
|
||||
});
|
||||
|
||||
it('Drag and drop columns', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('.ag-overlay-loading-wrapper').should('not.be.visible');
|
||||
cy.get('[col-id="marketName"]')
|
||||
.realMouseDown()
|
||||
.realMouseMove(700, 15)
|
||||
.realMouseUp();
|
||||
|
||||
// 7004-POSI-005
|
||||
cy.get('[col-id="marketName"]').should(($element) => {
|
||||
const attributeValue = $element.attr('aria-colindex');
|
||||
expect(attributeValue).not.to.equal('1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('sorting by ag-grid columns should work well', () => {
|
||||
it('sorting by Market', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
const marketsSortedDefault = [
|
||||
'ACTIVE MARKET',
|
||||
'Apple Monthly (30 Jun 2022)',
|
||||
'SUSPENDED MARKET',
|
||||
];
|
||||
const marketsSortedAsc = ['ACTIVE MARKET', 'Apple Monthly (30 Jun 2022)'];
|
||||
const marketsSortedDesc = [
|
||||
'SUSPENDED MARKET',
|
||||
'Apple Monthly (30 Jun 2022)',
|
||||
'ACTIVE MARKET',
|
||||
];
|
||||
cy.getByTestId('Positions').click();
|
||||
checkSorting(
|
||||
'marketName',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
it('I can see warnings', () => {
|
||||
visitAndClickPositions();
|
||||
|
||||
cy.get('[col-id="openVolume"]').within(() => {
|
||||
cy.get('[aria-label="warning-sign icon"]')
|
||||
.should('be.visible')
|
||||
.realHover();
|
||||
});
|
||||
// 7004-POSI-011
|
||||
cy.getByTestId(tooltipContent).should('be.visible');
|
||||
});
|
||||
|
||||
it('Positive and Negative color change', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(positions).click();
|
||||
// 7004-POSI-007
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="realisedPNL"]',
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
it('sorting by notional', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
const marketsSortedDefault = [
|
||||
'276,761.40348',
|
||||
'46,126.90058',
|
||||
'1,688.20',
|
||||
];
|
||||
const marketsSortedAsc = ['1,688.20', '46,126.90058', '276,761.40348'];
|
||||
const marketsSortedDesc = ['276,761.40348', '46,126.90058', '1,688.20'];
|
||||
cy.getByTestId('Positions').click();
|
||||
checkSorting(
|
||||
'notional',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="unrealisedPNL"]',
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
it('sorting by unrealisedPNL', () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
const marketsSortedDefault = ['8.95', '-0.22519', '8.95'];
|
||||
const marketsSortedAsc = ['-0.22519', '8.95', '8.95'];
|
||||
const marketsSortedDesc = ['8.95', '8.95', '-0.22519'];
|
||||
cy.getByTestId('Positions').click();
|
||||
checkSorting(
|
||||
'unrealisedPNL',
|
||||
marketsSortedDefault,
|
||||
marketsSortedAsc,
|
||||
marketsSortedDesc
|
||||
cy.get('.ag-center-cols-container').within(() => {
|
||||
assertPNLColor(
|
||||
'[col-id="openVolume"]',
|
||||
'text-vega-green',
|
||||
'text-vega-pink'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function validatePositionsDisplayed(multiKey = false) {
|
||||
cy.getByTestId('tab-positions').should('be.visible');
|
||||
cy.getByTestId('tab-positions').within(() => {
|
||||
it('View settlement asset', () => {
|
||||
visitAndClickPositions();
|
||||
cy.get('[col-id="asset"]').within(() => {
|
||||
cy.get('button[type="button"]').first().click();
|
||||
});
|
||||
// 7004-POSI-008
|
||||
cy.getByTestId(dialogContent).should('be.visible');
|
||||
cy.getByTestId(dialogCloseX).click();
|
||||
cy.getByTestId(dropDownMenu).first().click();
|
||||
cy.getByTestId(marketActionsContent).click();
|
||||
// 7004-POSI-009
|
||||
cy.getByTestId(dialogContent).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
function validatePositionsDisplayed(multiKey = false) {
|
||||
cy.getByTestId('tab-positions').should('be.visible');
|
||||
cy.getByTestId('tab-positions')
|
||||
.get('.ag-center-cols-container .ag-row')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('[col-id="marketName"]')
|
||||
.should('be.visible')
|
||||
.each(($marketSymbol) => {
|
||||
cy.wrap($marketSymbol).invoke('text').should('not.be.empty');
|
||||
});
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
|
||||
cy.get('.ag-center-cols-container [col-id="openVolume"]').each(
|
||||
($openVolume) => {
|
||||
cy.wrap($openVolume).invoke('text').should('not.be.empty');
|
||||
}
|
||||
);
|
||||
cy.get('[col-id="openVolume"]').should('not.be.empty');
|
||||
|
||||
// includes average entry price, mark price, realised PNL & leverage
|
||||
cy.getByTestId('flash-cell').each(($prices) => {
|
||||
cy.wrap($prices).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.getByTestId('flash-cell').should('not.be.empty');
|
||||
|
||||
if (!multiKey) {
|
||||
cy.get('[col-id="currentLeverage"]').should('contain.text', '2.846.1');
|
||||
cy.get('[col-id="currentLeverage"]').should('contain.text', '2,767.3');
|
||||
cy.get('[col-id="marginAccountBalance"]') // margin allocated
|
||||
.should('contain.text', '0.01');
|
||||
}
|
||||
|
||||
cy.get('[col-id="unrealisedPNL"]').each(($unrealisedPnl) => {
|
||||
cy.wrap($unrealisedPnl).invoke('text').should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get('[col-id="unrealisedPNL"]').should('not.be.empty');
|
||||
cy.get('[col-id="notional"]').should('contain.text', '276,761.40348'); // Total tDAI position
|
||||
cy.get('[col-id="realisedPNL"]').should('contain.text', '2.30'); // Total Realised PNL
|
||||
cy.get('[col-id="unrealisedPNL"]').should('contain.text', '8.95'); // Total Unrealised PNL
|
||||
|
||||
cy.get('.ag-header-row [col-id="notional"]')
|
||||
.should('contain.text', 'Notional')
|
||||
.realHover();
|
||||
cy.get('.ag-popup').should('contain.text', 'Mark price x open volume');
|
||||
});
|
||||
|
||||
cy.getByTestId('close-position').should('be.visible').and('have.length', 3);
|
||||
}
|
||||
});
|
||||
cy.get('.ag-header-row [col-id="notional"]')
|
||||
.should('contain.text', 'Notional')
|
||||
.realHover();
|
||||
cy.get('.ag-popup').should('contain.text', 'Mark price x open volume');
|
||||
|
||||
cy.getByTestId('close-position').should('be.visible').and('have.length', 3);
|
||||
}
|
||||
|
||||
function assertPNLColor(
|
||||
pnlSelector: string,
|
||||
positiveClass: string,
|
||||
negativeClass: string
|
||||
) {
|
||||
cy.get(pnlSelector).each(($el) => {
|
||||
const value = parseFloat($el.text());
|
||||
|
||||
if (value > 0) {
|
||||
cy.wrap($el).invoke('attr', 'class').should('contain', positiveClass);
|
||||
} else if (value < 0) {
|
||||
cy.wrap($el).invoke('attr', 'class').should('contain', negativeClass);
|
||||
} else if (value == 0) {
|
||||
cy.wrap($el)
|
||||
.invoke('attr', 'class')
|
||||
.should('not.contain', negativeClass, positiveClass);
|
||||
} else {
|
||||
throw new Error('Unexpected value');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function visitAndClickPositions() {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(positions).click();
|
||||
}
|
||||
|
||||
@@ -1,32 +1,79 @@
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
});
|
||||
const colHeader = '.ag-header-cell-text';
|
||||
const colIdPrice = '[col-id=price]';
|
||||
const colIdSize = '[col-id=size]';
|
||||
const colIdCreatedAt = '[col-id=createdAt]';
|
||||
const tradesTab = 'Trades';
|
||||
const tradesTable = 'tab-trades';
|
||||
|
||||
describe('trades', { tags: '@smoke' }, () => {
|
||||
const colIdPrice = 'price';
|
||||
const colIdSize = 'size';
|
||||
const colIdCreatedAt = 'createdAt';
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
});
|
||||
before(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId(tradesTab).click();
|
||||
});
|
||||
|
||||
it('renders trades', () => {
|
||||
cy.getByTestId('Trades').click();
|
||||
cy.getByTestId('tab-trades').should('be.visible');
|
||||
it('show trades', () => {
|
||||
// 6005-THIS-001
|
||||
// 6005-THIS-002
|
||||
cy.getByTestId(tradesTab).should('be.visible');
|
||||
cy.getByTestId(tradesTable).should('be.visible');
|
||||
cy.getByTestId(tradesTable).should('not.be.empty');
|
||||
});
|
||||
|
||||
cy.get(`[col-id=${colIdPrice}]`).each(($tradePrice) => {
|
||||
it('show trades prices', () => {
|
||||
// 6005-THIS-003
|
||||
cy.get(`${colIdPrice} ${colHeader}`).first().should('have.text', 'Price');
|
||||
cy.get(colIdPrice).each(($tradePrice) => {
|
||||
cy.wrap($tradePrice).invoke('text').should('not.be.empty');
|
||||
});
|
||||
cy.get(`[col-id=${colIdSize}]`).each(($tradeSize) => {
|
||||
});
|
||||
|
||||
it('show trades sizes', () => {
|
||||
// 6005-THIS-004
|
||||
cy.get(`${colIdSize} ${colHeader}`).first().should('have.text', 'Size');
|
||||
cy.get(colIdSize).each(($tradeSize) => {
|
||||
cy.wrap($tradeSize).invoke('text').should('not.be.empty');
|
||||
});
|
||||
});
|
||||
|
||||
it('show trades date and time', () => {
|
||||
// 6005-THIS-005
|
||||
cy.get(`${colIdCreatedAt} ${colHeader}`).should('have.text', 'Created at');
|
||||
const dateTimeRegex =
|
||||
/(\d{1,2})\/(\d{1,2})\/(\d{4}), (\d{1,2}):(\d{1,2}):(\d{1,2})/gm;
|
||||
cy.get(`[col-id=${colIdCreatedAt}]`).each(($tradeDateTime, index) => {
|
||||
cy.get(colIdCreatedAt).each(($tradeDateTime, index) => {
|
||||
if (index != 0) {
|
||||
//ignore header
|
||||
cy.wrap($tradeDateTime).invoke('text').should('match', dateTimeRegex);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('trades are sorted descending by datetime', () => {
|
||||
// 6005-THIS-006
|
||||
const dateTimes: Date[] = [];
|
||||
cy.get(colIdCreatedAt)
|
||||
.each(($tradeDateTime, index) => {
|
||||
if (index != 0) {
|
||||
//ignore header
|
||||
dateTimes.push(new Date($tradeDateTime.text()));
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
expect(dateTimes).to.deep.equal(
|
||||
dateTimes.sort((a, b) => b.getTime() - a.getTime())
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('copy price to deal ticket form', () => {
|
||||
// 6005-THIS-007
|
||||
cy.get(colIdPrice).last().click();
|
||||
cy.getByTestId('order-price').should('have.value', '171.16898');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,6 +31,8 @@ import {
|
||||
protocolUpgradeProposalsQuery,
|
||||
blockStatisticsQuery,
|
||||
networkParamQuery,
|
||||
liquidityProvisionsQuery,
|
||||
liquidityProviderFeeShareQuery,
|
||||
} from '@vegaprotocol/mock';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { MarketDataQuery, MarketsQuery } from '@vegaprotocol/markets';
|
||||
@@ -158,6 +160,12 @@ const mockTradingPage = (
|
||||
);
|
||||
aliasGQLQuery(req, 'Trades', tradesQuery());
|
||||
aliasGQLQuery(req, 'Chart', chartQuery());
|
||||
aliasGQLQuery(req, 'LiquidityProvisions', liquidityProvisionsQuery());
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'LiquidityProviderFeeShare',
|
||||
liquidityProviderFeeShareQuery
|
||||
);
|
||||
aliasGQLQuery(req, 'Candles', candlesQuery());
|
||||
aliasGQLQuery(req, 'Withdrawals', withdrawalsQuery());
|
||||
aliasGQLQuery(req, 'NetworkParams', networkParamsQuery());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user