Compare commits
145
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da9e4457b8 | ||
|
|
b8dcbd2e44 | ||
|
|
7c82144f37 | ||
|
|
17ad0cc975 | ||
|
|
eb58dcd350 | ||
|
|
c8c0bf2cc0 | ||
|
|
00579fcb1f | ||
|
|
5e13173efb | ||
|
|
3a6c0554cc | ||
|
|
d4b237a6ba | ||
|
|
5e765f3172 | ||
|
|
5ef8c11e6e | ||
|
|
84bae12def | ||
|
|
c5b22f5bfb | ||
|
|
071dcc61a8 | ||
|
|
ce0ccdfebc | ||
|
|
f1524d3fcd | ||
|
|
82e5128ba1 | ||
|
|
2bfc3abd15 | ||
|
|
bd3b557f3d | ||
|
|
c899da52c2 | ||
|
|
b9c4057ce5 | ||
|
|
d02feee5c6 | ||
|
|
6d1ab36a72 | ||
|
|
5690fe91a8 | ||
|
|
1daae6a233 | ||
|
|
cd35a34246 | ||
|
|
77ada964b5 | ||
|
|
d7404bcd76 | ||
|
|
91862701a7 | ||
|
|
0136efd78f | ||
|
|
c3a4954d0d | ||
|
|
528fd96721 | ||
|
|
155923ff8e | ||
|
|
5f7e60d22f | ||
|
|
351583ce8f | ||
|
|
88bf58b974 | ||
|
|
fcda4d7fcd | ||
|
|
b1b0039b33 | ||
|
|
6854980b32 | ||
|
|
d8aac83f2d | ||
|
|
5c17045752 | ||
|
|
8863209342 | ||
|
|
462bf6b8b5 | ||
|
|
e0b701e05a | ||
|
|
eca212eee0 | ||
|
|
c25858037a | ||
|
|
081f5b48e2 | ||
|
|
e306d1c9fa | ||
|
|
737dec4f5f | ||
|
|
6780b2f618 | ||
|
|
08dc60086d | ||
|
|
4595db07b0 | ||
|
|
c3da31146f | ||
|
|
b6a9faaa7c | ||
|
|
477d523582 | ||
|
|
a2b112d898 | ||
|
|
621ba497e8 | ||
|
|
a6964bc3cf | ||
|
|
48a9998441 | ||
|
|
bd1bd94ee7 | ||
|
|
2fdebbd694 | ||
|
|
96af8035d0 | ||
|
|
051e3da366 | ||
|
|
af5e666d5e | ||
|
|
333a7d6206 | ||
|
|
cb6b988466 | ||
|
|
806ea74f7e | ||
|
|
8693f3bfd8 | ||
|
|
58c6652e29 | ||
|
|
e8adff25c4 | ||
|
|
3e594a783a | ||
|
|
1f7117075b | ||
|
|
4c850ecead | ||
|
|
19f8fa909e | ||
|
|
8214858685 | ||
|
|
868f8e21dc | ||
|
|
6ead84b57c | ||
|
|
3975477985 | ||
|
|
8a0c15ac11 | ||
|
|
a4f512f946 | ||
|
|
88f3c278f8 | ||
|
|
34d5f3fd13 | ||
|
|
a060f94146 | ||
|
|
f649d78565 | ||
|
|
b611d30b31 | ||
|
|
545324ccd6 | ||
|
|
8c16759621 | ||
|
|
e724aac2f1 | ||
|
|
e3a6b75130 | ||
|
|
8d8f6b4928 | ||
|
|
6c1c5bf2a9 | ||
|
|
74a3aa8566 | ||
|
|
4cbd7a4928 | ||
|
|
201cf07a01 | ||
|
|
90ceeebf15 | ||
|
|
965f7f6e2d | ||
|
|
18633efec3 | ||
|
|
a0b758334a | ||
|
|
9f3026aa4b | ||
|
|
faa359e2fb | ||
|
|
1d178b940f | ||
|
|
b2dd053621 | ||
|
|
77f5193b7a | ||
|
|
055a0070db | ||
|
|
29b221c86a | ||
|
|
3e619acd4b | ||
|
|
c720719ac5 | ||
|
|
c676a7c1e2 | ||
|
|
ca63a671c8 | ||
|
|
4165f3905f | ||
|
|
a359ccb755 | ||
|
|
e584737005 | ||
|
|
b12c5ed39f | ||
|
|
d3dbd64cf1 | ||
|
|
2df62bca61 | ||
|
|
fd2a434b46 | ||
|
|
4e7a78f988 | ||
|
|
327619652a | ||
|
|
d2339205cc | ||
|
|
63df4cf465 | ||
|
|
5e34178291 | ||
|
|
0c44664aa5 | ||
|
|
7ef1d75529 | ||
|
|
84795b2d6a | ||
|
|
300019f108 | ||
|
|
2d0aebd3fe | ||
|
|
9e86d2aff5 | ||
|
|
0f7e76ae01 | ||
|
|
56732d1503 | ||
|
|
5c19263653 | ||
|
|
0d911b3029 | ||
|
|
9f059e7862 | ||
|
|
92ea93dadb | ||
|
|
6165aefad7 | ||
|
|
c95369d914 | ||
|
|
5dbc5d7997 | ||
|
|
47b3d5b55f | ||
|
|
da7c0b84f7 | ||
|
|
67e602ebb1 | ||
|
|
f407110e95 | ||
|
|
66a85cce2a | ||
|
|
93f8450ecb | ||
|
|
0447a6cf5d | ||
|
|
498be838c7 |
@@ -3,3 +3,7 @@ apps/**/node_modules/*
|
|||||||
tmp/*
|
tmp/*
|
||||||
.dockerignore
|
.dockerignore
|
||||||
dockerfiles
|
dockerfiles
|
||||||
|
node_modules
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: Release
|
||||||
|
about: A template to outline the steps needed to for a successful release of our frontend apps
|
||||||
|
title: 'Release [add dapp version]-core-[add core version]'
|
||||||
|
labels:
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
- [ ] Review [link to core release](xxx)
|
||||||
|
- [ ] Tag frontend-monorepo
|
||||||
|
- [ ] Create release and generate release notes
|
||||||
|
- [ ] Run `@smoke` tests
|
||||||
|
- [ ] Run `@regression` tests
|
||||||
|
- [ ] Run `@slow` tests
|
||||||
|
- [ ] Explorative testing of key flows
|
||||||
|
- [ ] Set `release/[network]` to tagged commit
|
||||||
|
- [ ] Verify builds (on Netlify and Fleek) are successful
|
||||||
|
- [ ] Verify build has been deployed
|
||||||
|
- [ ] Smoke testing on deployed app
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
name: Cypress tests - PR
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- synchronize
|
|
||||||
- ready_for_review
|
|
||||||
jobs:
|
|
||||||
pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout frontend mono repo
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
|
|
||||||
- name: Remove package.json & yarn.lock to avoid installing everything
|
|
||||||
run: rm package.json yarn.lock
|
|
||||||
|
|
||||||
- name: Install nx
|
|
||||||
run: yarn add nx
|
|
||||||
|
|
||||||
# Check SHAs
|
|
||||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
|
||||||
uses: nrwl/nx-set-shas@v2
|
|
||||||
with:
|
|
||||||
main-branch-name: ${{ github.base_ref || github.ref_name }}
|
|
||||||
set-environment-variables-for-job: true
|
|
||||||
|
|
||||||
# See affected apps
|
|
||||||
- name: See affected apps
|
|
||||||
run: |
|
|
||||||
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
|
|
||||||
echo -n "Affected projects: $affected"
|
|
||||||
projects=""
|
|
||||||
if [[ $affected == *"governance"* ]]; then projects+='"governance-e2e" '; fi
|
|
||||||
if [[ $affected == *"trading"* ]]; then projects+='"trading-e2e" '; fi
|
|
||||||
if [[ $affected == *"explorer"* ]]; then projects+='"explorer-e2e" '; fi
|
|
||||||
if [[ -z "$projects" ]]; then projects+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
|
||||||
projects=${projects%?}
|
|
||||||
projects=[${projects// /,}]
|
|
||||||
echo PROJECTS=$projects >> $GITHUB_ENV
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
projects: ${{ env.PROJECTS }}
|
|
||||||
|
|
||||||
run:
|
|
||||||
needs: pr
|
|
||||||
if: ${{ needs.pr.outputs.projects != '[]' }}
|
|
||||||
uses: ./.github/workflows/cypress-run.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
projects: ${{ needs.pr.outputs.projects }}
|
|
||||||
tags: '@smoke @regression'
|
|
||||||
|
|
||||||
# Report single result at the end, to avoid mess with required checks in PR
|
|
||||||
result:
|
|
||||||
if: ${{ always() }}
|
|
||||||
needs: run
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Cypress result
|
|
||||||
steps:
|
|
||||||
- run: |
|
|
||||||
result="${{ needs.run.result }}"
|
|
||||||
if [[ $result == "success" || $result == "skipped" ]]; then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
name: Cypress Run
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -17,6 +18,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
project: ${{ fromJSON(inputs.projects) }}
|
project: ${{ fromJSON(inputs.projects) }}
|
||||||
|
name: ${{ matrix.project }}
|
||||||
runs-on: self-hosted-runner
|
runs-on: self-hosted-runner
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
name: PR Validations
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
- ready_for_review
|
||||||
|
jobs:
|
||||||
|
pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check node version
|
||||||
|
id: node-version
|
||||||
|
run: |
|
||||||
|
npmVersion=$(cat .nvmrc | head -n 1)
|
||||||
|
echo ::set-output name=npmVersion::${npmVersion}
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ steps.node-version.outputs.npmVersion }}
|
||||||
|
|
||||||
|
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||||
|
uses: nrwl/nx-set-shas@v3
|
||||||
|
with:
|
||||||
|
main-branch-name: develop
|
||||||
|
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: '**/node_modules'
|
||||||
|
key: node_modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
|
||||||
|
- name: Install root dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: See affected apps
|
||||||
|
run: |
|
||||||
|
affected="$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=HEAD --select=projects)"
|
||||||
|
echo -n "Affected projects: $affected"
|
||||||
|
|
||||||
|
projects_e2e=""
|
||||||
|
if [[ $affected == *"governance"* ]]; then projects_e2e+='"governance-e2e" '; fi
|
||||||
|
if [[ $affected == *"trading"* ]]; then projects_e2e+='"trading-e2e" '; fi
|
||||||
|
if [[ $affected == *"explorer"* ]]; then projects_e2e+='"explorer-e2e" '; fi
|
||||||
|
if [[ -z "$projects_e2e" ]]; then projects_e2e+='"governance-e2e" "trading-e2e" "explorer-e2e" '; fi
|
||||||
|
projects_e2e=${projects_e2e%?}
|
||||||
|
projects_e2e=[${projects_e2e// /,}]
|
||||||
|
echo PROJECTS_E2E=$projects_e2e >> $GITHUB_ENV
|
||||||
|
echo PROJECTS=$(echo $projects_e2e | sed 's|-e2e||g') >> $GITHUB_ENV
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
projects: ${{ env.PROJECTS }}
|
||||||
|
projects-e2e: ${{ env.PROJECTS_E2E }}
|
||||||
|
|
||||||
|
run-cypress:
|
||||||
|
needs: pr
|
||||||
|
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||||
|
uses: ./.github/workflows/cypress-run.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
projects: ${{ needs.pr.outputs.projects-e2e }}
|
||||||
|
tags: '@smoke @regression'
|
||||||
|
|
||||||
|
run-docker-build:
|
||||||
|
needs: pr
|
||||||
|
if: ${{ needs.pr.outputs.projects != '[]' }}
|
||||||
|
uses: ./.github/workflows/publish-docker-containers.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
projects: ${{ needs.pr.outputs.projects }}
|
||||||
|
|
||||||
|
# Report single result at the end, to avoid mess with required checks in PR
|
||||||
|
result:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: run-cypress
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Cypress result
|
||||||
|
steps:
|
||||||
|
- run: |
|
||||||
|
result="${{ needs.run-cypress.result }}"
|
||||||
|
if [[ $result == "success" || $result == "skipped" ]]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -1,54 +1,23 @@
|
|||||||
name: Publish docker containers
|
name: Docker build
|
||||||
|
|
||||||
'on':
|
on:
|
||||||
push:
|
workflow_call:
|
||||||
tags:
|
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+-*'
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
inputs:
|
||||||
publish:
|
projects:
|
||||||
description: 'Publish tag to Docker Hub & GitHub Registry'
|
required: true
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
tag:
|
|
||||||
description: 'Git Tag to build and publish'
|
|
||||||
required: false
|
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
|
||||||
apps:
|
|
||||||
description: 'Applications to build and publish'
|
|
||||||
required: false
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- '["explorer", "token", "trading"]'
|
|
||||||
- '["explorer"]'
|
|
||||||
- '["token"]'
|
|
||||||
- '["trading"]'
|
|
||||||
archs:
|
|
||||||
description: 'Architecture to build and publish'
|
|
||||||
required: false
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- linux/amd64, linux/arm64
|
|
||||||
- linux/amd64
|
|
||||||
- linux/arm64
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
master:
|
master:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
app: ${{ fromJson(inputs.apps || '["explorer", "token", "trading"]') }}
|
app: ${{ fromJSON(inputs.projects) }}
|
||||||
name: Build the ${{ matrix.app }} image
|
name: ${{ matrix.app }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
ref: ${{ inputs.tag }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: quemu
|
id: quemu
|
||||||
@@ -60,67 +29,66 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Login to DockerHub
|
# https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||||
if: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
|
# https://github.com/actions/checkout#Checkout-pull-request-HEAD-commit-instead-of-merge-commit
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Determine Docker Image tag
|
- name: Determine Docker Image tag
|
||||||
id: tags
|
id: tags
|
||||||
run: |
|
run: |
|
||||||
hash=$(git rev-parse HEAD|cut -b1-8)
|
npmVersion=$(cat .nvmrc | head -n 1)
|
||||||
versionTag=${{ inputs.tag || startsWith(github.ref, 'refs/tags/') && github.ref_name || '${hash}' }}
|
versionTag=${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || github.event.pull_request.head.sha }}
|
||||||
|
echo ::set-output name=npmVersion::${npmVersion}
|
||||||
echo ::set-output name=version::${versionTag}
|
echo ::set-output name=version::${versionTag}
|
||||||
echo ::set-output name=npmVersion::$(cat dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }} | grep FROM | head -n 1 | awk '{print $2}' | cut -d ':' -f 2 | cut -d '-' -f 1 )
|
|
||||||
|
|
||||||
- name: Print config
|
- name: Print config
|
||||||
run: |
|
run: |
|
||||||
git rev-parse --verify HEAD
|
git rev-parse --verify HEAD
|
||||||
git status
|
git status
|
||||||
echo "inputs.tag=${{ inputs.tag }}"
|
|
||||||
echo "inputs.publish=${{ inputs.publish }}"
|
|
||||||
echo "inputs.apps=${{ inputs.apps }}"
|
|
||||||
echo "inputs.archs=${{ inputs.archs }}"
|
|
||||||
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
|
echo "steps.tags.outputs.version=${{ steps.tags.outputs.version }}"
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: ${{ steps.tags.outputs.npmVersion }}
|
|
||||||
|
|
||||||
- name: Build frontend dists
|
|
||||||
run: |
|
|
||||||
yarn --verbose --pure-lockfile
|
|
||||||
yarn nx ${{ matrix.app =='trading' && 'export' || 'build' }} ${{ matrix.app }} --pure-lockfile
|
|
||||||
|
|
||||||
- name: Build and export to local Docker
|
- name: Build and export to local Docker
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
|
||||||
push: false
|
|
||||||
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
|
|
||||||
build-args: APP=${{ matrix.app }}
|
|
||||||
load: true
|
load: true
|
||||||
tags: vegaprotocol/${{ matrix.app }}:local
|
build-args: |
|
||||||
|
APP=${{ matrix.app }}
|
||||||
|
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
|
||||||
|
|
||||||
- name: Sanity check docker image
|
- name: Sanity check docker image
|
||||||
run: |
|
run: |
|
||||||
docker run --rm vegaprotocol/${{ matrix.app }}:local cat .env
|
echo "Check .env file"
|
||||||
docker run --rm vegaprotocol/${{ matrix.app }}:local ls -lah
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat .env
|
||||||
|
echo "Check ipfs-hash"
|
||||||
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat ipfs-hash
|
||||||
|
echo "List html directory"
|
||||||
|
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local ls -lah
|
||||||
|
|
||||||
- name: Build and push to DockerHub
|
- name: Log in to the Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
push: true
|
||||||
push: ${{ inputs.publish || startsWith(github.ref, 'refs/tags/') }}
|
build-args: |
|
||||||
file: dockerfiles/${{ matrix.app =='trading' && 'Dockerfile.next' || 'Dockerfile.cra' }}.dist
|
APP=${{ matrix.app }}
|
||||||
build-args: APP=${{ matrix.app }}
|
NODE_VERSION=${{ steps.tags.outputs.npmVersion }}
|
||||||
platforms: ${{ inputs.archs || 'linux/amd64, linux/arm64' }}
|
|
||||||
tags: |
|
tags: |
|
||||||
vegaprotocol/${{ matrix.app }}:latest
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:latest
|
||||||
vegaprotocol/${{ matrix.app }}:${{ steps.tags.outputs.version }}
|
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ steps.tags.outputs.version }}
|
||||||
|
|
||||||
|
- name: Add preview label
|
||||||
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
labels: ${{ matrix.app }}-preview
|
||||||
|
number: ${{ github.event.number }}
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
|
- announcements
|
||||||
- ui-toolkit
|
- ui-toolkit
|
||||||
- react-helpers
|
- react-helpers
|
||||||
- tailwindcss-config
|
- tailwindcss-config
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# Build container
|
||||||
|
ARG NODE_VERSION
|
||||||
|
FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
|
||||||
|
WORKDIR /app
|
||||||
|
# Argument to allow building of different apps
|
||||||
|
ARG APP
|
||||||
|
RUN apk add --update --no-cache \
|
||||||
|
python3 \
|
||||||
|
make \
|
||||||
|
gcc \
|
||||||
|
g++
|
||||||
|
COPY . ./
|
||||||
|
RUN yarn --network-timeout 100000 --pure-lockfile
|
||||||
|
# work around for different build process in trading
|
||||||
|
RUN sh ./docker-build.sh
|
||||||
|
|
||||||
|
# Server environment
|
||||||
|
# if this fails you need to docker pull nginx:1.23-alpine and pin new SHA
|
||||||
|
# this is to ensure that we run always same version of alpine to make sure ipfs is indempotent
|
||||||
|
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
|
||||||
|
ARG APP
|
||||||
|
# configuration of system
|
||||||
|
RUN apk add --no-cache bash go-ipfs
|
||||||
|
EXPOSE 80
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
CMD ["/entrypoint.sh"]
|
||||||
|
|
||||||
|
# Copy dist
|
||||||
|
WORKDIR /usr/share/nginx/html
|
||||||
|
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY --from=build /app/dist/apps/${APP} /usr/share/nginx/html
|
||||||
|
COPY ./apps/${APP}/.env .env
|
||||||
|
RUN ipfs init && echo "$(ipfs add -rQ .)" > ipfs-hash
|
||||||
@@ -6,18 +6,10 @@ context('Home Page', function () {
|
|||||||
describe('Stats page', { tags: '@smoke' }, function () {
|
describe('Stats page', { tags: '@smoke' }, function () {
|
||||||
const statsValue = '[data-testid="stats-value"]';
|
const statsValue = '[data-testid="stats-value"]';
|
||||||
|
|
||||||
it('Should show connected environment', function () {
|
|
||||||
const deployedEnv = Cypress.env('environment').toUpperCase();
|
|
||||||
cy.get('[data-testid="stats-environment"]').should(
|
|
||||||
'have.text',
|
|
||||||
`/ ${deployedEnv}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show connected environment stats', function () {
|
it('should show connected environment stats', function () {
|
||||||
const statTitles = {
|
const statTitles = {
|
||||||
0: 'Status',
|
0: 'Status',
|
||||||
1: 'Height',
|
1: 'Block height',
|
||||||
2: 'Uptime',
|
2: 'Uptime',
|
||||||
3: 'Total nodes',
|
3: 'Total nodes',
|
||||||
4: 'Total staked',
|
4: 'Total staked',
|
||||||
@@ -36,27 +28,27 @@ context('Home Page', function () {
|
|||||||
|
|
||||||
cy.get('[data-testid="stats-title"]')
|
cy.get('[data-testid="stats-title"]')
|
||||||
.each(($list, index) => {
|
.each(($list, index) => {
|
||||||
cy.wrap($list).should('have.text', statTitles[index]);
|
cy.wrap($list).should('contain.text', statTitles[index]);
|
||||||
})
|
})
|
||||||
.then(($list) => {
|
.then(($list) => {
|
||||||
cy.wrap($list).should('have.length', 16);
|
cy.wrap($list).should('have.length', 16);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(statsValue).eq(0).should('have.text', 'CONNECTED');
|
cy.get(statsValue).eq(0).should('contain.text', 'CONNECTED');
|
||||||
cy.get(statsValue).eq(1).should('not.be.empty');
|
cy.get(statsValue).eq(1).should('not.be.empty');
|
||||||
cy.get(statsValue)
|
cy.get(statsValue)
|
||||||
.eq(2)
|
.eq(2)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('match', /\d+d \d+h \d+m \d+s/i);
|
.should('match', /\d+d \d+h \d+m \d+s/i);
|
||||||
cy.get(statsValue).eq(3).should('have.text', '2');
|
cy.get(statsValue).eq(3).should('contain.text', '2');
|
||||||
cy.get(statsValue)
|
cy.get(statsValue)
|
||||||
.eq(4)
|
.eq(4)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('match', /\d+\.\d\d(?!\d)/i);
|
.should('match', /\d+\.\d\d(?!\d)/i);
|
||||||
cy.get(statsValue).eq(5).should('have.text', '0');
|
cy.get(statsValue).eq(5).should('contain.text', '0');
|
||||||
cy.get(statsValue).eq(6).should('have.text', '0');
|
cy.get(statsValue).eq(6).should('contain.text', '0');
|
||||||
cy.get(statsValue).eq(7).should('have.text', '0');
|
cy.get(statsValue).eq(7).should('contain.text', '0');
|
||||||
cy.get(statsValue).eq(8).should('have.text', '0');
|
cy.get(statsValue).eq(8).should('contain.text', '0');
|
||||||
cy.get(statsValue).eq(9).should('not.be.empty');
|
cy.get(statsValue).eq(9).should('not.be.empty');
|
||||||
cy.get(statsValue).eq(10).should('not.be.empty');
|
cy.get(statsValue).eq(10).should('not.be.empty');
|
||||||
cy.get(statsValue).eq(11).should('not.be.empty');
|
cy.get(statsValue).eq(11).should('not.be.empty');
|
||||||
@@ -86,75 +78,4 @@ context('Home Page', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Git info', function () {
|
|
||||||
it('git info is rendered on the footer of the page', function () {
|
|
||||||
cy.getByTestId('git-info').within(() => {
|
|
||||||
cy.getByTestId('git-network-data').within(() => {
|
|
||||||
cy.contains('Reading network data from').should('be.visible');
|
|
||||||
cy.get('span').should('have.text', Cypress.env('networkQueryUrl'));
|
|
||||||
cy.getByTestId('link').should('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.getByTestId('git-eth-data').within(() => {
|
|
||||||
cy.contains('Reading Ethereum data from').should('be.visible');
|
|
||||||
cy.get('span').should('have.text', Cypress.env('ethUrl'));
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.getByTestId('git-commit-hash').within(() => {
|
|
||||||
cy.contains('Version/commit hash:').should('be.visible');
|
|
||||||
cy.getByTestId('link').should('have.text', Cypress.env('commitHash'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Search bar', function () {
|
|
||||||
it('Successful search for specific id by block id', function () {
|
|
||||||
const blockId = '973624';
|
|
||||||
search(blockId);
|
|
||||||
cy.url().should('include', blockId);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Successful search for specific id by tx hash', function () {
|
|
||||||
const txHash =
|
|
||||||
'9ED3718AA8308E7E08EC588EE7AADAF49711D2138860D8914B4D81A2054D9FB8';
|
|
||||||
search(txHash);
|
|
||||||
cy.url().should('include', txHash);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Successful search for specific id by tx id', function () {
|
|
||||||
const txId =
|
|
||||||
'0x61DCCEBB955087F50D0B85382DAE138EDA9631BF1A4F92E563D528904AA38898';
|
|
||||||
search(txId);
|
|
||||||
cy.url().should('include', txId);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Error message displayed when invalid search by wrong string length', function () {
|
|
||||||
search('9ED3718AA8308E7E08EC588EE7AADAF497D2138860D8914B4D81A2054D9FB8');
|
|
||||||
validateSearchError("Something doesn't look right");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Error message displayed when invalid search by invalid hash', function () {
|
|
||||||
search(
|
|
||||||
'9ED3718AA8308E7E08ECht8EE753DAF49711D2138860D8914B4D81A2054D9FB8'
|
|
||||||
);
|
|
||||||
validateSearchError('Transaction is not hexadecimal');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Error message displayed when searching empty field', function () {
|
|
||||||
cy.get('[data-testid="search"]').clear();
|
|
||||||
cy.get('[data-testid="search-button"]').click();
|
|
||||||
validateSearchError('Search required');
|
|
||||||
});
|
|
||||||
|
|
||||||
function search(searchTxt) {
|
|
||||||
cy.get('[data-testid="search"]').clear().type(searchTxt);
|
|
||||||
cy.get('[data-testid="search-button"]').click();
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateSearchError(expectedError) {
|
|
||||||
cy.get('[data-testid="search-error"]').should('have.text', expectedError);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ NX_TENDERMINT_URL=http://localhost:26617
|
|||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
|
||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|||||||
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://dev.token.vega.xyz
|
||||||
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -6,3 +6,4 @@ NX_VEGA_ENV=MAINNET
|
|||||||
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
|
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/
|
||||||
NX_ETHERSCAN_URL=https://etherscan.io
|
NX_ETHERSCAN_URL=https://etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
@@ -6,6 +6,7 @@ NX_VEGA_ENV=MIRROR
|
|||||||
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
|
NX_BLOCK_EXPLORER=https://be.mainnet-mirror.vega.xyz/rest/
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://mainnet-mirror.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
|
|
||||||
# App flags
|
# App flags
|
||||||
NX_EXPLORER_ASSETS=1
|
NX_EXPLORER_ASSETS=1
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
|
|||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.sandbox.vega.xyz/websocket
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -11,3 +11,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket
|
|||||||
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://stagnet1.token.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -5,3 +5,4 @@ NX_VEGA_ENV=STAGNET3
|
|||||||
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||||
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
|
||||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
|
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -8,3 +8,4 @@ NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
|
|||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
|
NX_VEGA_GOVERNANCE_URL=https://token.fairground.wtf
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATOR_TESTNET
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api.validators-testnet.vega.xyz/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|
||||||
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
|
NX_VEGA_GOVERNANCE_URL=https://validator-testnet.governance.vega.xyz
|
||||||
NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.xyz
|
NX_TENDERMINT_URL=https://tm-be.validators-testnet.vega.rocks
|
||||||
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.xyz/rest
|
NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/
|
||||||
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
|
|||||||
NX_VEGA_ENV=CUSTOM
|
NX_VEGA_ENV=CUSTOM
|
||||||
NX_BLOCK_EXPLORER=
|
NX_BLOCK_EXPLORER=
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||||
|
|||||||
@@ -1,87 +1,21 @@
|
|||||||
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
|
import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment';
|
||||||
import { Header } from './components/header';
|
|
||||||
import { Main } from './components/main';
|
|
||||||
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
||||||
import { Footer } from './components/footer/footer';
|
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
|
||||||
AnnouncementBanner,
|
|
||||||
ExternalLink,
|
|
||||||
Icon,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import {
|
|
||||||
AssetDetailsDialog,
|
|
||||||
useAssetDetailsDialogStore,
|
|
||||||
} from '@vegaprotocol/assets';
|
|
||||||
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client';
|
||||||
import classNames from 'classnames';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { useState } from 'react';
|
import { router } from './routes/router-config';
|
||||||
|
|
||||||
const DialogsContainer = () => {
|
const splashLoading = (
|
||||||
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
<Splash>
|
||||||
return (
|
<Loader />
|
||||||
<AssetDetailsDialog
|
</Splash>
|
||||||
assetId={id}
|
);
|
||||||
trigger={trigger || null}
|
|
||||||
asJson={asJson}
|
|
||||||
open={isOpen}
|
|
||||||
onChange={setOpen}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const MainnetSimAd = () => {
|
|
||||||
const [shouldDisplayBanner, setShouldDisplayBanner] = useState<boolean>(true);
|
|
||||||
|
|
||||||
// Return an empty div so that the grid layout in _app.page.ts
|
|
||||||
// renders correctly
|
|
||||||
if (!shouldDisplayBanner) {
|
|
||||||
return <div />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AnnouncementBanner>
|
|
||||||
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
|
|
||||||
<button
|
|
||||||
className="flex items-center"
|
|
||||||
onClick={() => setShouldDisplayBanner(false)}
|
|
||||||
>
|
|
||||||
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
|
|
||||||
</button>
|
|
||||||
<div>
|
|
||||||
<span className="pr-4">Mainnet sim 3 is live!</span>
|
|
||||||
<ExternalLink href="https://fairground.wtf/">Learn more</ExternalLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</AnnouncementBanner>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<TendermintWebsocketProvider>
|
<TendermintWebsocketProvider>
|
||||||
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
<NetworkLoader cache={DEFAULT_CACHE_CONFIG}>
|
||||||
<div
|
<RouterProvider router={router} fallbackElement={splashLoading} />
|
||||||
className={classNames(
|
|
||||||
'max-w-[1500px] min-h-[100vh]',
|
|
||||||
'mx-auto my-0',
|
|
||||||
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
|
||||||
'border-vega-light-200 dark:border-vega-dark-200 lg:border-l lg:border-r',
|
|
||||||
'antialiased text-black dark:text-white',
|
|
||||||
'overflow-hidden relative'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<Header />
|
|
||||||
<MainnetSimAd />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Main />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Footer />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<DialogsContainer />
|
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
</TendermintWebsocketProvider>
|
</TendermintWebsocketProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const Footer = () => {
|
|||||||
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
|
const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false);
|
||||||
const { screenSize } = useScreenDimensions();
|
const { screenSize } = useScreenDimensions();
|
||||||
const showFullFeedbackLabel = useMemo(
|
const showFullFeedbackLabel = useMemo(
|
||||||
() => ['lg', 'xl'].includes(screenSize),
|
() => ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize),
|
||||||
[screenSize]
|
[screenSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jest.mock('../search', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const renderComponent = () => (
|
const renderComponent = () => (
|
||||||
<MemoryRouter>
|
<MemoryRouter initialEntries={['/txs']}>
|
||||||
<Header />
|
<Header />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
@@ -24,6 +24,7 @@ describe('Header', () => {
|
|||||||
|
|
||||||
expect(screen.getByTestId('navigation')).toHaveTextContent('Explorer');
|
expect(screen.getByTestId('navigation')).toHaveTextContent('Explorer');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render search', () => {
|
it('should render search', () => {
|
||||||
render(renderComponent());
|
render(renderComponent());
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { matchPath, useLocation } from 'react-router-dom';
|
import { matchPath, useLocation, useMatch } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ThemeSwitcher,
|
ThemeSwitcher,
|
||||||
Navigation,
|
Navigation,
|
||||||
@@ -13,23 +13,26 @@ import { t } from '@vegaprotocol/i18n';
|
|||||||
import { Routes } from '../../routes/route-names';
|
import { Routes } from '../../routes/route-names';
|
||||||
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||||
import type { Navigable } from '../../routes/router-config';
|
import type { Navigable } from '../../routes/router-config';
|
||||||
import routerConfig from '../../routes/router-config';
|
import { isNavigable } from '../../routes/router-config';
|
||||||
|
import { routerConfig } from '../../routes/router-config';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { Search } from '../search';
|
import { Search } from '../search';
|
||||||
|
|
||||||
const routeToNavigationItem = (r: Navigable) => (
|
const routeToNavigationItem = (r: Navigable) => (
|
||||||
<NavigationItem key={r.name}>
|
<NavigationItem key={r.handle.name}>
|
||||||
<NavigationLink to={r.path}>{r.text}</NavigationLink>
|
<NavigationLink to={r.path}>{r.handle.text}</NavigationLink>
|
||||||
</NavigationItem>
|
</NavigationItem>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
|
const pages = routerConfig[0].children || [];
|
||||||
const mainItems = compact(
|
const mainItems = compact(
|
||||||
[Routes.TX, Routes.BLOCKS, Routes.ORACLES, Routes.VALIDATORS].map((n) =>
|
[Routes.TX, Routes.BLOCKS, Routes.ORACLES, Routes.VALIDATORS].map((n) =>
|
||||||
routerConfig.find((r) => r.path === n)
|
pages.find((r) => r.path === n)
|
||||||
)
|
)
|
||||||
);
|
).filter(isNavigable);
|
||||||
|
|
||||||
const groupedItems = compact(
|
const groupedItems = compact(
|
||||||
[
|
[
|
||||||
@@ -39,8 +42,8 @@ export const Header = () => {
|
|||||||
Routes.GOVERNANCE,
|
Routes.GOVERNANCE,
|
||||||
Routes.NETWORK_PARAMETERS,
|
Routes.NETWORK_PARAMETERS,
|
||||||
Routes.GENESIS,
|
Routes.GENESIS,
|
||||||
].map((n) => routerConfig.find((r) => r.path === n))
|
].map((n) => pages.find((r) => r.path === n))
|
||||||
);
|
).filter(isNavigable);
|
||||||
|
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
@@ -67,7 +70,7 @@ export const Header = () => {
|
|||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
<Search />
|
{!isHome && <Search />}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
onResize={(width, el) => {
|
onResize={(width, el) => {
|
||||||
@@ -90,7 +93,7 @@ export const Header = () => {
|
|||||||
hide={[NavigationBreakpoint.Small, NavigationBreakpoint.Narrow]}
|
hide={[NavigationBreakpoint.Small, NavigationBreakpoint.Narrow]}
|
||||||
>
|
>
|
||||||
{mainItems.map(routeToNavigationItem)}
|
{mainItems.map(routeToNavigationItem)}
|
||||||
{groupedItems && (
|
{groupedItems && groupedItems.length > 0 && (
|
||||||
<NavigationItem>
|
<NavigationItem>
|
||||||
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
<NavigationTrigger isActive={Boolean(isOnOther)}>
|
||||||
{t('Other')}
|
{t('Other')}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import { AppRouter } from '../../routes';
|
|
||||||
|
|
||||||
export const Main = () => {
|
|
||||||
return (
|
|
||||||
<main className="p-4">
|
|
||||||
<AppRouter />
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,143 +1,52 @@
|
|||||||
import {
|
|
||||||
addDecimalsFormatNumber,
|
|
||||||
formatNumberPercentage,
|
|
||||||
getMarketExpiryDateFormatted,
|
|
||||||
} from '@vegaprotocol/utils';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
|
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
|
||||||
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
import { LiquidityInfoPanel } from '@vegaprotocol/market-info';
|
||||||
|
import { LiquidityMonitoringParametersInfoPanel } from '@vegaprotocol/market-info';
|
||||||
import {
|
import {
|
||||||
MarketStateMapping,
|
InstrumentInfoPanel,
|
||||||
MarketTradingModeMapping,
|
KeyDetailsInfoPanel,
|
||||||
} from '@vegaprotocol/types';
|
LiquidityPriceRangeInfoPanel,
|
||||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
MetadataInfoPanel,
|
||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
OracleInfoPanel,
|
||||||
import BigNumber from 'bignumber.js';
|
RiskFactorsInfoPanel,
|
||||||
import { useMemo } from 'react';
|
RiskModelInfoPanel,
|
||||||
|
RiskParametersInfoPanel,
|
||||||
|
SettlementAssetInfoPanel,
|
||||||
|
} from '@vegaprotocol/market-info';
|
||||||
|
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||||
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
|
|
||||||
const assetId = useMemo(
|
|
||||||
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
|
|
||||||
[market]
|
|
||||||
);
|
|
||||||
const { data: asset } = useAssetDataProvider(assetId ?? '');
|
|
||||||
|
|
||||||
if (!market) return null;
|
if (!market) return null;
|
||||||
|
|
||||||
const keyDetails = {
|
|
||||||
decimalPlaces: market.decimalPlaces,
|
|
||||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
|
||||||
tradingMode: market.tradingMode,
|
|
||||||
state: MarketStateMapping[market.state],
|
|
||||||
};
|
|
||||||
const assetDecimals =
|
|
||||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
|
||||||
|
|
||||||
const liquidityPriceRange = formatNumberPercentage(
|
|
||||||
new BigNumber(market.lpPriceRange).times(100)
|
|
||||||
);
|
|
||||||
|
|
||||||
const panels = [
|
const panels = [
|
||||||
{
|
{
|
||||||
title: t('Key details'),
|
title: t('Key details'),
|
||||||
content: (
|
content: <KeyDetailsInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{
|
|
||||||
name: market.tradableInstrument.instrument.name,
|
|
||||||
marketID: market.id,
|
|
||||||
tradingMode:
|
|
||||||
keyDetails.tradingMode &&
|
|
||||||
MarketTradingModeMapping[keyDetails.tradingMode],
|
|
||||||
marketDecimalPlaces: market.decimalPlaces,
|
|
||||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
|
||||||
settlementAssetDecimalPlaces: assetDecimals,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Instrument'),
|
title: t('Instrument'),
|
||||||
content: (
|
content: <InstrumentInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{
|
|
||||||
marketName: market.tradableInstrument.instrument.name,
|
|
||||||
code: market.tradableInstrument.instrument.code,
|
|
||||||
productType:
|
|
||||||
market.tradableInstrument.instrument.product.__typename,
|
|
||||||
...market.tradableInstrument.instrument.product,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Settlement asset'),
|
title: t('Settlement asset'),
|
||||||
content: asset ? (
|
content: <SettlementAssetInfoPanel market={market} noBorder={false} />,
|
||||||
<AssetDetailsTable
|
|
||||||
asset={asset}
|
|
||||||
inline={true}
|
|
||||||
noBorder={false}
|
|
||||||
dtClassName="text-black dark:text-white text-ui !px-0 !font-normal"
|
|
||||||
ddClassName="text-black dark:text-white text-ui !px-0 !font-normal max-w-full"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Splash>{t('No data')}</Splash>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Metadata'),
|
title: t('Metadata'),
|
||||||
content: (
|
content: <MetadataInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{
|
|
||||||
expiryDate: getMarketExpiryDateFormatted(
|
|
||||||
market.tradableInstrument.instrument.metadata.tags
|
|
||||||
),
|
|
||||||
...market.tradableInstrument.instrument.metadata.tags
|
|
||||||
?.map((tag) => {
|
|
||||||
const [key, value] = tag.split(':');
|
|
||||||
return { [key]: value };
|
|
||||||
})
|
|
||||||
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Risk model'),
|
title: t('Risk model'),
|
||||||
content: (
|
content: <RiskModelInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={market.tradableInstrument.riskModel}
|
|
||||||
unformatted={true}
|
|
||||||
omits={[]}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Risk parameters'),
|
title: t('Risk parameters'),
|
||||||
content: (
|
content: <RiskParametersInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={market.tradableInstrument.riskModel.params}
|
|
||||||
unformatted={true}
|
|
||||||
omits={[]}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Risk factors'),
|
title: t('Risk factors'),
|
||||||
content: (
|
content: <RiskFactorsInfoPanel noBorder={false} market={market} />,
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={market.riskFactors}
|
|
||||||
unformatted={true}
|
|
||||||
omits={['market', '__typename']}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
...(market.priceMonitoringSettings?.parameters?.triggers || []).map(
|
||||||
(trigger, i) => ({
|
(trigger, i) => ({
|
||||||
@@ -158,7 +67,10 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
<MarketInfoTable
|
<MarketInfoTable
|
||||||
noBorder={false}
|
noBorder={false}
|
||||||
data={{ referencePrice: trigger.referencePrice }}
|
data={{ referencePrice: trigger.referencePrice }}
|
||||||
decimalPlaces={assetDecimals}
|
decimalPlaces={
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset
|
||||||
|
.decimals
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@@ -166,64 +78,26 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
{
|
{
|
||||||
title: t('Liquidity monitoring parameters'),
|
title: t('Liquidity monitoring parameters'),
|
||||||
content: (
|
content: (
|
||||||
<MarketInfoTable
|
<LiquidityMonitoringParametersInfoPanel
|
||||||
noBorder={false}
|
noBorder={false}
|
||||||
data={{
|
market={market}
|
||||||
triggeringRatio:
|
|
||||||
market.liquidityMonitoringParameters.triggeringRatio,
|
|
||||||
...market.liquidityMonitoringParameters.targetStakeParameters,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t('Liquidity'),
|
||||||
|
content: <LiquidityInfoPanel market={market} noBorder={false} />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t('Liquidity price range'),
|
title: t('Liquidity price range'),
|
||||||
content: (
|
content: (
|
||||||
<>
|
<LiquidityPriceRangeInfoPanel market={market} noBorder={false} />
|
||||||
<p className="text-xs mb-4">
|
|
||||||
{`For liquidity orders to count towards a commitment, they must be
|
|
||||||
within the liquidity monitoring bounds.`}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs mb-4">
|
|
||||||
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
|
|
||||||
price.`}
|
|
||||||
</p>
|
|
||||||
<MarketInfoTable
|
|
||||||
noBorder={false}
|
|
||||||
data={{
|
|
||||||
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
|
|
||||||
lowestPrice:
|
|
||||||
market.data?.midPrice &&
|
|
||||||
`${addDecimalsFormatNumber(
|
|
||||||
new BigNumber(1)
|
|
||||||
.minus(market.lpPriceRange)
|
|
||||||
.times(market.data.midPrice)
|
|
||||||
.toString(),
|
|
||||||
market.decimalPlaces
|
|
||||||
)} ${quoteUnit}`,
|
|
||||||
highestPrice:
|
|
||||||
market.data?.midPrice &&
|
|
||||||
`${addDecimalsFormatNumber(
|
|
||||||
new BigNumber(1)
|
|
||||||
.plus(market.lpPriceRange)
|
|
||||||
.times(market.data.midPrice)
|
|
||||||
.toString(),
|
|
||||||
market.decimalPlaces
|
|
||||||
)} ${quoteUnit}`,
|
|
||||||
}}
|
|
||||||
></MarketInfoTable>
|
|
||||||
</>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Oracle'),
|
title: t('Oracle'),
|
||||||
content: (
|
content: (
|
||||||
<MarketInfoTable
|
<OracleInfoPanel noBorder={false} market={market}>
|
||||||
noBorder={false}
|
|
||||||
data={
|
|
||||||
market.tradableInstrument.instrument.product.dataSourceSpecBinding
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Link
|
<Link
|
||||||
className="text-xs hover:underline"
|
className="text-xs hover:underline"
|
||||||
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
|
to={`/oracles#${market.tradableInstrument.instrument.product.dataSourceSpecForSettlementData.id}`}
|
||||||
@@ -236,7 +110,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
>
|
>
|
||||||
{t('View termination oracle specification')}
|
{t('View termination oracle specification')}
|
||||||
</Link>
|
</Link>
|
||||||
</MarketInfoTable>
|
</OracleInfoPanel>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -244,7 +118,7 @@ export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{panels.map((p) => (
|
{panels.map((p) => (
|
||||||
<div className="mb-3">
|
<div key={p.title} className="mb-3">
|
||||||
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
<h2 className="font-alpha calt text-xl">{p.title}</h2>
|
||||||
{p.content}
|
{p.content}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
import { StatusMessage } from '../status-message';
|
import { StatusMessage } from '../status-message';
|
||||||
|
|
||||||
interface RenderFetchedProps {
|
interface RenderFetchedProps {
|
||||||
@@ -7,6 +8,7 @@ interface RenderFetchedProps {
|
|||||||
loading: boolean | undefined;
|
loading: boolean | undefined;
|
||||||
className?: string;
|
className?: string;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
|
refetch?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RenderFetched = ({
|
export const RenderFetched = ({
|
||||||
@@ -15,6 +17,7 @@ export const RenderFetched = ({
|
|||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
errorMessage = t('Error retrieving data'),
|
errorMessage = t('Error retrieving data'),
|
||||||
|
refetch,
|
||||||
}: RenderFetchedProps) => {
|
}: RenderFetchedProps) => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@@ -23,7 +26,20 @@ export const RenderFetched = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <StatusMessage className={className}>{errorMessage}</StatusMessage>;
|
return (
|
||||||
|
<>
|
||||||
|
<StatusMessage className={className}>{errorMessage}</StatusMessage>
|
||||||
|
{refetch && (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
refetch();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Try again')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface RouteErrorBoundaryProps {
|
|
||||||
children: React.ReactElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RouteErrorBoundary extends React.Component<
|
|
||||||
RouteErrorBoundaryProps,
|
|
||||||
{ hasError: boolean }
|
|
||||||
> {
|
|
||||||
constructor(props: RouteErrorBoundaryProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = { hasError: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
static getDerivedStateFromError() {
|
|
||||||
return { hasError: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
override componentDidCatch(error: Error) {
|
|
||||||
console.log(`Error caught in App error boundary ${error.message}`, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
override render() {
|
|
||||||
if (this.state.hasError) {
|
|
||||||
return <h1>{t('Something went wrong')}</h1>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.props.children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,189 +1,70 @@
|
|||||||
import {
|
import {
|
||||||
detectTypeByFetching,
|
determineType,
|
||||||
detectTypeFromQuery,
|
|
||||||
getSearchType,
|
|
||||||
isBlock,
|
isBlock,
|
||||||
isHexadecimal,
|
|
||||||
isNetworkParty,
|
isNetworkParty,
|
||||||
isNonHex,
|
|
||||||
SearchTypes,
|
SearchTypes,
|
||||||
toHex,
|
isHash,
|
||||||
toNonHex,
|
|
||||||
} from './detect-search';
|
} from './detect-search';
|
||||||
import { DATA_SOURCES } from '../../config';
|
|
||||||
|
|
||||||
global.fetch = jest.fn();
|
global.fetch = jest.fn();
|
||||||
|
|
||||||
describe('Detect Search', () => {
|
describe('Detect Search', () => {
|
||||||
it("should detect that it's a hexadecimal", () => {
|
it.each([
|
||||||
const expected = true;
|
['0000000000000000000000000000000000000000000000000000000000000000', true],
|
||||||
const testString =
|
['0000000000000000000000000000000000000000000000000000000000000001', true],
|
||||||
'0x073ceaab59e5f2dd0561dec4883e7ee5bc7165cd4de34717a3ab8f2cbe3007f9';
|
[
|
||||||
const actual = isHexadecimal(testString);
|
'LOOONG0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
expect(actual).toBe(expected);
|
false,
|
||||||
});
|
],
|
||||||
|
['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', false],
|
||||||
it("should detect that it's not hexadecimal", () => {
|
['something else', false],
|
||||||
const expected = true;
|
])("should detect that it's a hash", (input, expected) => {
|
||||||
const testString =
|
expect(isHash(input)).toBe(expected);
|
||||||
'073ceaab59e5f2dd0561dec4883e7ee5bc7165cd4de34717a3ab8f2cbe3007f9';
|
|
||||||
const actual = isNonHex(testString);
|
|
||||||
expect(actual).toBe(expected);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should detect that it's a network party", () => {
|
it("should detect that it's a network party", () => {
|
||||||
const expected = true;
|
expect(isNetworkParty('network')).toBe(true);
|
||||||
const testString = 'network';
|
expect(isNetworkParty('web')).toBe(false);
|
||||||
const actual = isNetworkParty(testString);
|
|
||||||
expect(actual).toBe(expected);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should detect that it's a block", () => {
|
it("should detect that it's a block", () => {
|
||||||
const expected = true;
|
expect(isBlock('123')).toBe(true);
|
||||||
const testString = '3188';
|
expect(isBlock('x123')).toBe(false);
|
||||||
const actual = isBlock(testString);
|
|
||||||
expect(actual).toBe(expected);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should convert from non-hex to hex', () => {
|
it.each([
|
||||||
const expected = '0x123';
|
[
|
||||||
const testString = '123';
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
const actual = toHex(testString);
|
SearchTypes.Transaction,
|
||||||
expect(actual).toBe(expected);
|
],
|
||||||
});
|
[
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000001',
|
||||||
it('should convert from hex to non-hex', () => {
|
SearchTypes.Party,
|
||||||
const expected = '123';
|
],
|
||||||
const testString = '0x123';
|
['123', SearchTypes.Block],
|
||||||
const actual = toNonHex(testString);
|
['network', SearchTypes.Party],
|
||||||
expect(actual).toBe(expected);
|
['something else', SearchTypes.Unknown],
|
||||||
});
|
])(
|
||||||
|
"detectTypeByFetching should call fetch with non-hex query it's a transaction",
|
||||||
it("should detect type client side from query if it's a hexadecimal", () => {
|
async (input, type) => {
|
||||||
const expected = [SearchTypes.Party, SearchTypes.Transaction];
|
// @ts-ignore issue related to polyfill
|
||||||
const testString =
|
fetch.mockImplementation(
|
||||||
'0x4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
jest.fn(() =>
|
||||||
const actual = detectTypeFromQuery(testString);
|
Promise.resolve({
|
||||||
expect(actual).toStrictEqual(expected);
|
ok:
|
||||||
});
|
input ===
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
it("should detect type client side from query if it's a non hex", () => {
|
json: () =>
|
||||||
const expected = [SearchTypes.Party, SearchTypes.Transaction];
|
Promise.resolve({
|
||||||
const testString =
|
transaction: {
|
||||||
'4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
hash: input,
|
||||||
const actual = detectTypeFromQuery(testString);
|
},
|
||||||
expect(actual).toStrictEqual(expected);
|
}),
|
||||||
});
|
})
|
||||||
|
)
|
||||||
it("should detect type client side from query if it's a network party", () => {
|
);
|
||||||
const expected = [SearchTypes.Party];
|
const result = await determineType(input);
|
||||||
const testString = 'network';
|
expect(result).toBe(type);
|
||||||
const actual = detectTypeFromQuery(testString);
|
}
|
||||||
expect(actual).toStrictEqual(expected);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
it("should detect type client side from query if it's a block (number)", () => {
|
|
||||||
const expected = [SearchTypes.Block];
|
|
||||||
const testString = '23432';
|
|
||||||
const actual = detectTypeFromQuery(testString);
|
|
||||||
expect(actual).toStrictEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("detectTypeByFetching should call fetch with non-hex query it's a transaction", async () => {
|
|
||||||
const query = '0xabc';
|
|
||||||
const type = SearchTypes.Transaction;
|
|
||||||
// @ts-ignore issue related to polyfill
|
|
||||||
fetch.mockImplementation(
|
|
||||||
jest.fn(() =>
|
|
||||||
Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
json: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
transaction: {
|
|
||||||
hash: query,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const result = await detectTypeByFetching(query);
|
|
||||||
expect(fetch).toHaveBeenCalledWith(
|
|
||||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(query)}`
|
|
||||||
);
|
|
||||||
expect(result).toBe(type);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("detectTypeByFetching should call fetch with non-hex query it's a party", async () => {
|
|
||||||
const query = 'abc';
|
|
||||||
const type = SearchTypes.Party;
|
|
||||||
// @ts-ignore issue related to polyfill
|
|
||||||
fetch.mockImplementation(
|
|
||||||
jest.fn(() =>
|
|
||||||
Promise.resolve({
|
|
||||||
ok: false,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const result = await detectTypeByFetching(query);
|
|
||||||
expect(result).toBe(type);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSearchType should return party from fetch response', async () => {
|
|
||||||
const query =
|
|
||||||
'0x4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
|
||||||
const expected = SearchTypes.Party;
|
|
||||||
// @ts-ignore issue related to polyfill
|
|
||||||
fetch.mockImplementation(
|
|
||||||
jest.fn(() =>
|
|
||||||
Promise.resolve({
|
|
||||||
ok: false,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSearchType should return transaction from fetch response', async () => {
|
|
||||||
const query =
|
|
||||||
'4624293CFE3D8B67A0AB448BAFF8FBCF1A1B770D9D5F263761D3D6CBEA94D97F';
|
|
||||||
const expected = SearchTypes.Transaction;
|
|
||||||
// @ts-ignore issue related to polyfill
|
|
||||||
fetch.mockImplementation(
|
|
||||||
jest.fn(() =>
|
|
||||||
Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
json: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
transaction: {
|
|
||||||
hash: query,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSearchType should return undefined from transaction response', async () => {
|
|
||||||
const query = 'u';
|
|
||||||
const expected = undefined;
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSearchType should return block if query is number', async () => {
|
|
||||||
const query = '123';
|
|
||||||
const expected = SearchTypes.Block;
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSearchType should return party if query is network', async () => {
|
|
||||||
const query = 'network';
|
|
||||||
const expected = SearchTypes.Party;
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
expect(result).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
import { DATA_SOURCES } from '../../config';
|
import { DATA_SOURCES } from '../../config';
|
||||||
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
|
||||||
|
|
||||||
@@ -6,15 +7,20 @@ export enum SearchTypes {
|
|||||||
Party = 'party',
|
Party = 'party',
|
||||||
Block = 'block',
|
Block = 'block',
|
||||||
Order = 'order',
|
Order = 'order',
|
||||||
|
Unknown = 'unknown',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TX_LENGTH = 64;
|
export const HASH_LENGTH = 64;
|
||||||
|
|
||||||
|
export const isHash = (value: string) =>
|
||||||
|
/[0-9a-fA-F]+/.test(remove0x(value)) &&
|
||||||
|
remove0x(value).length === HASH_LENGTH;
|
||||||
|
|
||||||
export const isHexadecimal = (search: string) =>
|
export const isHexadecimal = (search: string) =>
|
||||||
search.startsWith('0x') && search.length === 2 + TX_LENGTH;
|
search.startsWith('0x') && search.length === 2 + HASH_LENGTH;
|
||||||
|
|
||||||
export const isNonHex = (search: string) =>
|
export const isNonHex = (search: string) =>
|
||||||
!search.startsWith('0x') && search.length === TX_LENGTH;
|
!search.startsWith('0x') && search.length === HASH_LENGTH;
|
||||||
|
|
||||||
export const isBlock = (search: string) => !Number.isNaN(Number(search));
|
export const isBlock = (search: string) => !Number.isNaN(Number(search));
|
||||||
|
|
||||||
@@ -23,121 +29,44 @@ export const isNetworkParty = (search: string) => search === 'network';
|
|||||||
export const toHex = (query: string) =>
|
export const toHex = (query: string) =>
|
||||||
isHexadecimal(query) ? query : `0x${query}`;
|
isHexadecimal(query) ? query : `0x${query}`;
|
||||||
|
|
||||||
export const toNonHex = (query: string) =>
|
export const toNonHex = remove0x;
|
||||||
isNonHex(query) ? query : `${query.replace('0x', '')}`;
|
|
||||||
|
|
||||||
export const detectTypeFromQuery = (
|
/**
|
||||||
query: string
|
* Determine the type of the given query
|
||||||
): SearchTypes[] | undefined => {
|
*/
|
||||||
const i = query.toLowerCase();
|
export const determineType = async (query: string): Promise<SearchTypes> => {
|
||||||
|
const value = query.toLowerCase();
|
||||||
if (isHexadecimal(i) || isNonHex(i)) {
|
if (isHash(value)) {
|
||||||
return [SearchTypes.Party, SearchTypes.Transaction];
|
// it can be either `SearchTypes.Party` or `SearchTypes.Transaction`
|
||||||
} else if (isNetworkParty(i)) {
|
if (await isTransactionHash(value)) {
|
||||||
return [SearchTypes.Party];
|
return SearchTypes.Transaction;
|
||||||
} else if (isBlock(i)) {
|
} else {
|
||||||
return [SearchTypes.Block];
|
return SearchTypes.Party;
|
||||||
|
}
|
||||||
|
} else if (isNetworkParty(value)) {
|
||||||
|
return SearchTypes.Party;
|
||||||
|
} else if (isBlock(value)) {
|
||||||
|
return SearchTypes.Block;
|
||||||
}
|
}
|
||||||
|
return SearchTypes.Unknown;
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const detectTypeByFetching = async (
|
/**
|
||||||
query: string
|
* Checks if given input is a transaction hash by querying the transactions
|
||||||
): Promise<SearchTypes | undefined> => {
|
* endpoint
|
||||||
const hash = toNonHex(query);
|
*/
|
||||||
|
export const isTransactionHash = async (input: string): Promise<boolean> => {
|
||||||
|
const hash = remove0x(input);
|
||||||
const request = await fetch(
|
const request = await fetch(
|
||||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
|
`${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (request?.ok) {
|
if (request?.ok) {
|
||||||
const body: BlockExplorerTransaction = await request.json();
|
const body: BlockExplorerTransaction = await request.json();
|
||||||
|
|
||||||
if (body?.transaction) {
|
if (body?.transaction) {
|
||||||
return SearchTypes.Transaction;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SearchTypes.Party;
|
return false;
|
||||||
};
|
|
||||||
|
|
||||||
// Code commented out because the current solution to detect a hex is temporary (by process of elimination)
|
|
||||||
// export const detectTypeByFetching = async (
|
|
||||||
// query: string,
|
|
||||||
// type: SearchTypes
|
|
||||||
// ): Promise<SearchTypes | undefined> => {
|
|
||||||
// const TYPES = [SearchTypes.Party, SearchTypes.Transaction];
|
|
||||||
//
|
|
||||||
// if (!TYPES.includes(type)) {
|
|
||||||
// throw new Error('Search type provided not recognised');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (type === SearchTypes.Transaction) {
|
|
||||||
// const hash = toNonHex(query);
|
|
||||||
// const request = await fetch(
|
|
||||||
// `${DATA_SOURCES.blockExplorerUrl}/transactions/${hash}`
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (request?.ok) {
|
|
||||||
// const body: BlockExplorerTransaction = await request.json();
|
|
||||||
//
|
|
||||||
// if (body?.transaction) {
|
|
||||||
// return SearchTypes.Transaction;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else if (type === SearchTypes.Party) {
|
|
||||||
// const party = toNonHex(query);
|
|
||||||
//
|
|
||||||
// const request = await fetch(
|
|
||||||
// `${DATA_SOURCES.blockExplorerUrl}/transactions?limit=1&filters[tx.submitter]=${party}`
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (request.ok) {
|
|
||||||
// const body: BlockExplorerTransactions = await request.json();
|
|
||||||
//
|
|
||||||
// if (body?.transactions?.length) {
|
|
||||||
// return SearchTypes.Party;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return undefined;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const getSearchType = async (
|
|
||||||
// query: string
|
|
||||||
// ): Promise<SearchTypes | undefined> => {
|
|
||||||
// const searchTypes = detectTypeFromQuery(query);
|
|
||||||
// const hasResults = searchTypes?.length;
|
|
||||||
//
|
|
||||||
// if (hasResults) {
|
|
||||||
// if (hasResults > 1) {
|
|
||||||
// const promises = searchTypes.map((type) =>
|
|
||||||
// detectTypeByFetching(query, type)
|
|
||||||
// );
|
|
||||||
// const results = await Promise.all(promises);
|
|
||||||
// return results.find((result) => result !== undefined);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return searchTypes[0];
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return undefined;
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const getSearchType = async (
|
|
||||||
query: string
|
|
||||||
): Promise<SearchTypes | undefined> => {
|
|
||||||
const searchTypes = detectTypeFromQuery(query);
|
|
||||||
const hasResults = searchTypes?.length;
|
|
||||||
|
|
||||||
if (hasResults) {
|
|
||||||
if (hasResults > 1) {
|
|
||||||
return await detectTypeByFetching(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
return searchTypes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,157 +1,82 @@
|
|||||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
import {
|
||||||
import { Search } from './search';
|
act,
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import { SearchForm } from './search';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { Routes } from '../../routes/route-names';
|
import { Routes } from '../../routes/route-names';
|
||||||
import { SearchTypes, getSearchType } from './detect-search';
|
|
||||||
|
|
||||||
|
global.fetch = jest.fn();
|
||||||
const mockedNavigate = jest.fn();
|
const mockedNavigate = jest.fn();
|
||||||
const mockGetSearchType = getSearchType as jest.MockedFunction<
|
|
||||||
typeof getSearchType
|
|
||||||
>;
|
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
...jest.requireActual('react-router-dom'),
|
...jest.requireActual('react-router-dom'),
|
||||||
useNavigate: () => mockedNavigate,
|
useNavigate: () => mockedNavigate,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('./detect-search', () => ({
|
|
||||||
...jest.requireActual('./detect-search'),
|
|
||||||
getSearchType: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedNavigate.mockClear();
|
mockedNavigate.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderComponent = () => (
|
const renderComponent = () =>
|
||||||
<MemoryRouter>
|
render(
|
||||||
<Search />
|
<MemoryRouter>
|
||||||
</MemoryRouter>
|
<SearchForm />
|
||||||
);
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
|
||||||
const getInputs = () => ({
|
describe('SearchForm', () => {
|
||||||
input: screen.getByTestId('search'),
|
|
||||||
button: screen.getByTestId('search-button'),
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Search', () => {
|
|
||||||
it('should render search input and button', () => {
|
it('should render search input and button', () => {
|
||||||
render(renderComponent());
|
renderComponent();
|
||||||
expect(screen.getByTestId('search')).toBeInTheDocument();
|
expect(screen.getByTestId('search')).toBeInTheDocument();
|
||||||
expect(screen.getByTestId('search-button')).toHaveTextContent('Search');
|
expect(screen.getByTestId('search-button')).toHaveTextContent('Search');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render error if input is not known', async () => {
|
it.each([
|
||||||
render(renderComponent());
|
[
|
||||||
const { button, input } = getInputs();
|
Routes.TX,
|
||||||
fireEvent.change(input, { target: { value: 'asd' } });
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
fireEvent.click(button);
|
],
|
||||||
|
[
|
||||||
expect(await screen.findByTestId('search-error')).toHaveTextContent(
|
Routes.PARTIES,
|
||||||
'Transaction type is not recognised'
|
'0000000000000000000000000000000000000000000000000000000000000001',
|
||||||
|
],
|
||||||
|
[Routes.BLOCKS, '123'],
|
||||||
|
[undefined, 'something else'],
|
||||||
|
])('should redirect to %s', async (route, input) => {
|
||||||
|
// @ts-ignore issue related to polyfill
|
||||||
|
fetch.mockImplementation(
|
||||||
|
jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
ok:
|
||||||
|
input ===
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
json: () =>
|
||||||
|
Promise.resolve({
|
||||||
|
transaction: {
|
||||||
|
hash: input,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
renderComponent();
|
||||||
|
await act(async () => {
|
||||||
it('should render error if no input is given', async () => {
|
fireEvent.change(screen.getByTestId('search'), {
|
||||||
render(renderComponent());
|
target: {
|
||||||
const { button } = getInputs();
|
value: input,
|
||||||
|
},
|
||||||
fireEvent.click(button);
|
});
|
||||||
|
fireEvent.click(screen.getByTestId('search-button'));
|
||||||
expect(await screen.findByTestId('search-error')).toHaveTextContent(
|
|
||||||
'Search query required'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should redirect to transactions page', async () => {
|
|
||||||
render(renderComponent());
|
|
||||||
const { button, input } = getInputs();
|
|
||||||
mockGetSearchType.mockResolvedValue(SearchTypes.Transaction);
|
|
||||||
fireEvent.change(input, {
|
|
||||||
target: {
|
|
||||||
value:
|
|
||||||
'0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(button);
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(mockedNavigate).toBeCalledWith(
|
expect(mockedNavigate).toBeCalledTimes(route ? 1 : 0);
|
||||||
`${Routes.TX}/0x1234567890123456789012345678901234567890123456789012345678901234`
|
if (route) {
|
||||||
);
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
});
|
expect(mockedNavigate).toBeCalledWith(`${route}/${input}`);
|
||||||
});
|
}
|
||||||
|
|
||||||
it('should redirect to transactions page without proceeding 0x', async () => {
|
|
||||||
render(renderComponent());
|
|
||||||
const { button, input } = getInputs();
|
|
||||||
mockGetSearchType.mockResolvedValue(SearchTypes.Transaction);
|
|
||||||
fireEvent.change(input, {
|
|
||||||
target: {
|
|
||||||
value:
|
|
||||||
'1234567890123456789012345678901234567890123456789012345678901234',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fireEvent.click(button);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockedNavigate).toBeCalledWith(
|
|
||||||
`${Routes.TX}/0x1234567890123456789012345678901234567890123456789012345678901234`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should redirect to parties page', async () => {
|
|
||||||
render(renderComponent());
|
|
||||||
const { button, input } = getInputs();
|
|
||||||
mockGetSearchType.mockResolvedValue(SearchTypes.Party);
|
|
||||||
fireEvent.change(input, {
|
|
||||||
target: {
|
|
||||||
value:
|
|
||||||
'0x1234567890123456789012345678901234567890123456789012345678901234',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fireEvent.click(button);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockedNavigate).toBeCalledWith(
|
|
||||||
`${Routes.PARTIES}/0x1234567890123456789012345678901234567890123456789012345678901234`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should redirect to parties page without proceeding 0x', async () => {
|
|
||||||
render(renderComponent());
|
|
||||||
const { button, input } = getInputs();
|
|
||||||
mockGetSearchType.mockResolvedValue(SearchTypes.Party);
|
|
||||||
fireEvent.change(input, {
|
|
||||||
target: {
|
|
||||||
value:
|
|
||||||
'1234567890123456789012345678901234567890123456789012345678901234',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fireEvent.click(button);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockedNavigate).toBeCalledWith(
|
|
||||||
`${Routes.PARTIES}/0x1234567890123456789012345678901234567890123456789012345678901234`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should redirect to blocks page if passed a number', async () => {
|
|
||||||
render(renderComponent());
|
|
||||||
const { button, input } = getInputs();
|
|
||||||
mockGetSearchType.mockResolvedValue(SearchTypes.Block);
|
|
||||||
fireEvent.change(input, {
|
|
||||||
target: {
|
|
||||||
value: '123',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fireEvent.click(button);
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockedNavigate).toBeCalledWith(`${Routes.BLOCKS}/123`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Button, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
import { Button, Input, InputError } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { getSearchType, SearchTypes, toHex } from './detect-search';
|
|
||||||
import { Routes } from '../../routes/route-names';
|
import { Routes } from '../../routes/route-names';
|
||||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
|
import { determineType, isBlock, isHash, SearchTypes } from './detect-search';
|
||||||
|
|
||||||
interface FormFields {
|
interface FormFields {
|
||||||
search: string;
|
search: string;
|
||||||
@@ -30,101 +31,26 @@ const MagnifyingGlass = () => (
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const Clear = () => (
|
||||||
|
<svg
|
||||||
|
className="w-3 h-3"
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11.3748 1.37478L1.37478 11.3748L0.625244 10.6252L10.6252 0.625244L11.3748 1.37478Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1.37478 0.625244L11.3748 10.6252L10.6252 11.3748L0.625244 1.37478L1.37478 0.625244Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
export const Search = () => {
|
export const Search = () => {
|
||||||
const { register, handleSubmit } = useForm<FormFields>();
|
const searchForm = <SearchForm />;
|
||||||
const navigate = useNavigate();
|
|
||||||
const [error, setError] = useState<Error | null>(null);
|
|
||||||
|
|
||||||
const onSubmit = useCallback(
|
|
||||||
async (fields: FormFields) => {
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
const query = fields.search;
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
return setError(new Error(t('Search query required')));
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await getSearchType(query);
|
|
||||||
const urlAsHex = toHex(query);
|
|
||||||
const unrecognisedError = new Error(
|
|
||||||
t('Transaction type is not recognised')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
switch (result) {
|
|
||||||
case SearchTypes.Party:
|
|
||||||
return navigate(`${Routes.PARTIES}/${urlAsHex}`);
|
|
||||||
case SearchTypes.Transaction:
|
|
||||||
return navigate(`${Routes.TX}/${urlAsHex}`);
|
|
||||||
case SearchTypes.Block:
|
|
||||||
return navigate(`${Routes.BLOCKS}/${Number(query)}`);
|
|
||||||
default:
|
|
||||||
return setError(unrecognisedError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return setError(unrecognisedError);
|
|
||||||
},
|
|
||||||
[navigate]
|
|
||||||
);
|
|
||||||
|
|
||||||
const searchForm = (
|
|
||||||
<form className="block min-w-[290px]" onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<div className="flex relative items-stretch gap-2 text-xs">
|
|
||||||
<label htmlFor="search" className="sr-only">
|
|
||||||
{t('Search by block number or transaction hash')}
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
className={classNames(
|
|
||||||
'absolute top-[50%] translate-y-[-50%] left-2',
|
|
||||||
'text-vega-light-300 dark:text-vega-dark-300'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<MagnifyingGlass />
|
|
||||||
</button>
|
|
||||||
<Input
|
|
||||||
{...register('search')}
|
|
||||||
id="search"
|
|
||||||
data-testid="search"
|
|
||||||
className={classNames(
|
|
||||||
'peer',
|
|
||||||
'pl-8 py-2 text-xs',
|
|
||||||
'border rounded border-vega-light-200 dark:border-vega-dark-200'
|
|
||||||
)}
|
|
||||||
hasError={Boolean(error?.message)}
|
|
||||||
type="text"
|
|
||||||
placeholder={t('Enter block number, public key or transaction hash')}
|
|
||||||
/>
|
|
||||||
{error?.message && (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'hidden peer-focus:block',
|
|
||||||
'bg-white dark:bg-black',
|
|
||||||
'border rounded-b border-t-0 border-vega-light-200 dark:border-vega-dark-200',
|
|
||||||
'absolute top-[100%] flex-1 w-full pb-2 px-2 text-black dark:text-white'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<InputError
|
|
||||||
data-testid="search-error"
|
|
||||||
intent="danger"
|
|
||||||
className="text-xs"
|
|
||||||
>
|
|
||||||
{error.message}
|
|
||||||
</InputError>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
className="hidden [.search-dropdown_&]:block"
|
|
||||||
type="submit"
|
|
||||||
size="xs"
|
|
||||||
data-testid="search-button"
|
|
||||||
>
|
|
||||||
{t('Search')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
|
|
||||||
const searchTrigger = (
|
const searchTrigger = (
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
@@ -154,10 +80,135 @@ export const Search = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="hidden [.nav-search-full_&]:block">{searchForm}</div>
|
<div className="hidden [.nav-search-full_&]:block min-w-[290px]">
|
||||||
|
{searchForm}
|
||||||
|
</div>
|
||||||
<div className="hidden [.nav-search-compact_&]:block">
|
<div className="hidden [.nav-search-compact_&]:block">
|
||||||
{searchTrigger}
|
{searchTrigger}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SearchForm = () => {
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
setError,
|
||||||
|
clearErrors,
|
||||||
|
formState,
|
||||||
|
watch,
|
||||||
|
} = useForm<FormFields>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const onSubmit = useCallback(
|
||||||
|
async (fields: FormFields) => {
|
||||||
|
clearErrors();
|
||||||
|
const type = await determineType(fields.search);
|
||||||
|
if (type) {
|
||||||
|
switch (type) {
|
||||||
|
case SearchTypes.Party:
|
||||||
|
return navigate(`${Routes.PARTIES}/${remove0x(fields.search)}`);
|
||||||
|
case SearchTypes.Transaction:
|
||||||
|
return navigate(`${Routes.TX}/${remove0x(fields.search)}`);
|
||||||
|
case SearchTypes.Block:
|
||||||
|
return navigate(`${Routes.BLOCKS}/${Number(fields.search)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setError('search', new Error(t('The search term is not a valid query')));
|
||||||
|
},
|
||||||
|
[clearErrors, navigate, setError]
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchQuery = watch('search', '');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className="block min-w-[200px]" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="flex relative items-stretch gap-2 text-xs">
|
||||||
|
<div className="relative w-full">
|
||||||
|
<label htmlFor="search" className="sr-only">
|
||||||
|
{t('Search by block number or transaction hash')}
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
className={classNames(
|
||||||
|
'absolute top-[50%] translate-y-[-50%] left-2',
|
||||||
|
'text-vega-light-300 dark:text-vega-dark-300'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<MagnifyingGlass />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setValue('search', '');
|
||||||
|
clearErrors();
|
||||||
|
}}
|
||||||
|
className={classNames(
|
||||||
|
{ hidden: searchQuery.length === 0 },
|
||||||
|
'absolute top-[50%] translate-y-[-50%] right-2',
|
||||||
|
'text-vega-light-300 dark:text-vega-dark-300'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Clear />
|
||||||
|
</button>
|
||||||
|
<Input
|
||||||
|
{...register('search', {
|
||||||
|
required: t('Search query is required'),
|
||||||
|
validate: (value) =>
|
||||||
|
isHash(value) ||
|
||||||
|
isBlock(value) ||
|
||||||
|
t('Search query has to be a number or a 64 character hash'),
|
||||||
|
onBlur: () => clearErrors('search'),
|
||||||
|
})}
|
||||||
|
id="search"
|
||||||
|
data-testid="search"
|
||||||
|
className={classNames(
|
||||||
|
'pl-8 py-2 text-xs',
|
||||||
|
{ 'pr-8': searchQuery.length > 1 },
|
||||||
|
'border rounded border-vega-light-200 dark:border-vega-dark-200',
|
||||||
|
{
|
||||||
|
'border-vega-pink dark:border-vega-pink': Boolean(
|
||||||
|
formState.errors.search
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
hasError={Boolean(formState.errors.search)}
|
||||||
|
type="text"
|
||||||
|
placeholder={t(
|
||||||
|
'Enter block number, public key or transaction hash'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{formState.errors.search && (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'[nav_&]:border [nav_&]:rounded [nav_&]:border-vega-light-300 [nav_&]:dark:border-vega-light-300',
|
||||||
|
'[.search-dropdown_&]:border [.search-dropdown_&]:rounded [.search-dropdown_&]:border-vega-light-300 [.search-dropdown_&]:dark:border-vega-light-300',
|
||||||
|
'bg-white dark:bg-black',
|
||||||
|
'absolute top-[100%] flex-1 w-full pb-2 px-2 text-black dark:text-white'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<InputError
|
||||||
|
data-testid="search-error"
|
||||||
|
intent="danger"
|
||||||
|
className="text-xs"
|
||||||
|
>
|
||||||
|
{formState.errors.search.message}
|
||||||
|
</InputError>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
size="xs"
|
||||||
|
data-testid="search-button"
|
||||||
|
className="[nav_&]:hidden"
|
||||||
|
>
|
||||||
|
{t('Search')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { StatsManager } from '@vegaprotocol/network-stats';
|
import { StatsManager } from '@vegaprotocol/network-stats';
|
||||||
|
import { SearchForm } from '../../components/search';
|
||||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const classnames = 'mt-4 grid grid-cols-1 lg:grid-cols-2 lg:gap-4';
|
const classnames = 'mt-4 mb-4';
|
||||||
|
|
||||||
useDocumentTitle();
|
useDocumentTitle();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<StatsManager className={classnames} />
|
<div className="p-20 max-sm:py-10 max-sm:px-0">
|
||||||
|
<SearchForm />
|
||||||
|
</div>
|
||||||
|
<div className="px-20 max-sm:px-0">
|
||||||
|
<StatsManager className={classnames} />
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { useRoutes } from 'react-router-dom';
|
|
||||||
import { RouteErrorBoundary } from '../components/router-error-boundary';
|
|
||||||
|
|
||||||
import routerConfig from './router-config';
|
|
||||||
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
|
|
||||||
|
|
||||||
export interface RouteChildProps {
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AppRouter = () => {
|
|
||||||
const routes = useRoutes(routerConfig);
|
|
||||||
|
|
||||||
const splashLoading = (
|
|
||||||
<Splash>
|
|
||||||
<Loader />
|
|
||||||
</Splash>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RouteErrorBoundary>
|
|
||||||
<React.Suspense fallback={splashLoading}>{routes}</React.Suspense>
|
|
||||||
</RouteErrorBoundary>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import {
|
||||||
|
AssetDetailsDialog,
|
||||||
|
useAssetDetailsDialogStore,
|
||||||
|
} from '@vegaprotocol/assets';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
|
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||||
|
import {
|
||||||
|
BackgroundVideo,
|
||||||
|
BreadcrumbsContainer,
|
||||||
|
ButtonLink,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
isRouteErrorResponse,
|
||||||
|
Link,
|
||||||
|
Outlet,
|
||||||
|
useMatch,
|
||||||
|
useRouteError,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import { Footer } from '../components/footer/footer';
|
||||||
|
import { Header } from '../components/header';
|
||||||
|
import { Routes } from './route-names';
|
||||||
|
|
||||||
|
const DialogsContainer = () => {
|
||||||
|
const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore();
|
||||||
|
return (
|
||||||
|
<AssetDetailsDialog
|
||||||
|
assetId={id}
|
||||||
|
trigger={trigger || null}
|
||||||
|
asJson={asJson}
|
||||||
|
open={isOpen}
|
||||||
|
onChange={setOpen}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Layout = () => {
|
||||||
|
const isHome = Boolean(useMatch(Routes.HOME));
|
||||||
|
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'max-w-[1500px] min-h-[100vh]',
|
||||||
|
'mx-auto my-0',
|
||||||
|
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
||||||
|
'border-vega-light-200 dark:border-vega-dark-200 lg:border-l lg:border-r',
|
||||||
|
'antialiased text-black dark:text-white',
|
||||||
|
'overflow-hidden relative'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||||
|
<AnnouncementBanner
|
||||||
|
app="explorer"
|
||||||
|
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Header />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<main className="p-4">
|
||||||
|
{!isHome && <BreadcrumbsContainer className="mb-4" />}
|
||||||
|
<Outlet />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogsContainer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ErrorBoundary = () => {
|
||||||
|
const error = useRouteError();
|
||||||
|
|
||||||
|
const errorTitle = isRouteErrorResponse(error)
|
||||||
|
? `${error.status} ${error.statusText}`
|
||||||
|
: t('Something went wrong');
|
||||||
|
|
||||||
|
const errorMessage = isRouteErrorResponse(error)
|
||||||
|
? error.error?.message
|
||||||
|
: (error as Error).message || JSON.stringify(error);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BackgroundVideo className="brightness-50" />
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'max-w-[620px] p-2 mt-[10vh]',
|
||||||
|
'mx-auto my-0',
|
||||||
|
'antialiased text-white',
|
||||||
|
'overflow-hidden relative',
|
||||||
|
'flex flex-col gap-2'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div>{GHOST}</div>
|
||||||
|
<h1 className="text-[2.7rem] font-alpha calt break-words uppercase">
|
||||||
|
{errorTitle}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm mt-10 overflow-auto break-all font-mono">
|
||||||
|
{errorMessage}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ButtonLink onClick={() => window.location.reload()}>
|
||||||
|
{t('Try refreshing')}
|
||||||
|
</ButtonLink>{' '}
|
||||||
|
{t('or go back to')}{' '}
|
||||||
|
<Link className="underline" to="/">
|
||||||
|
{t('Home')}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GHOST = (
|
||||||
|
<svg
|
||||||
|
width="56"
|
||||||
|
height="85"
|
||||||
|
viewBox="0 0 56 85"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path d="M41 0.5H3V60.5H41V0.5Z" fill="white" />
|
||||||
|
<path d="M15 18.5H13V20.5H15V18.5Z" fill="black" />
|
||||||
|
<path d="M17 20.5H15V22.5H17V20.5Z" fill="black" />
|
||||||
|
<path d="M19 18.5H17V20.5H19V18.5Z" fill="black" />
|
||||||
|
<path d="M15 22.5H13V24.5H15V22.5Z" fill="black" />
|
||||||
|
<path d="M19 22.5H17V24.5H19V22.5Z" fill="black" />
|
||||||
|
<path d="M29 28.5H15V30.5H29V28.5Z" fill="black" />
|
||||||
|
<path d="M27 18.5H25V20.5H27V18.5Z" fill="black" />
|
||||||
|
<path d="M29 20.5H27V22.5H29V20.5Z" fill="black" />
|
||||||
|
<path d="M31 18.5H29V20.5H31V18.5Z" fill="black" />
|
||||||
|
<path d="M27 22.5H25V24.5H27V22.5Z" fill="black" />
|
||||||
|
<path d="M31 22.5H29V24.5H31V22.5Z" fill="black" />
|
||||||
|
<path d="M31 26.5H29V28.5H31V26.5Z" fill="black" />
|
||||||
|
<path d="M19 60.5H17V84.5H19V60.5Z" fill="black" />
|
||||||
|
<path d="M27 60.5H25V84.5H27V60.5Z" fill="black" />
|
||||||
|
<path
|
||||||
|
d="M3 42.5V58.64V60.5V64.5H21V60.5H23V64.5H41V60.5V58.64V42.5H3Z"
|
||||||
|
fill="#FF077F"
|
||||||
|
/>
|
||||||
|
<path d="M35 46.5H41V42.5H3V46.5H31H35Z" fill="#CB0666" />
|
||||||
|
<path d="M3 32.32V29.5L0 32.5V60.5H2V33.33L3 32.32Z" fill="black" />
|
||||||
|
<path d="M41 31.8V29.49L54.79 21.53L55.79 23.26L41 31.8Z" fill="black" />
|
||||||
|
<path d="M36 54.5H35V55.5H36V54.5Z" fill="black" />
|
||||||
|
<path d="M35 53.5H34V54.5H35V53.5Z" fill="black" />
|
||||||
|
<path d="M34 48.5H33V53.5H34V48.5Z" fill="black" />
|
||||||
|
<path d="M38 48.5H37V52.5H38V48.5Z" fill="black" />
|
||||||
|
<path d="M37 53.5H36V54.5H37V53.5Z" fill="black" />
|
||||||
|
<path d="M39 52.5H38V53.5H39V52.5Z" fill="black" />
|
||||||
|
<path
|
||||||
|
d="M55.7901 23.27L53.0601 22.54L45.1001 8.75L46.8301 7.75L55.7901 23.27Z"
|
||||||
|
fill="black"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
@@ -8,7 +8,7 @@ import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
|||||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
|
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
|
||||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
import { marketInfoWithDataProvider } from '@vegaprotocol/market-info';
|
||||||
import { PageTitle } from '../../components/page-helpers/page-title';
|
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||||
|
|
||||||
export const MarketPage = () => {
|
export const MarketPage = () => {
|
||||||
@@ -17,7 +17,7 @@ export const MarketPage = () => {
|
|||||||
const { marketId } = useParams<{ marketId: string }>();
|
const { marketId } = useParams<{ marketId: string }>();
|
||||||
|
|
||||||
const { data, loading, error } = useDataProvider({
|
const { data, loading, error } = useDataProvider({
|
||||||
dataProvider: marketInfoProvider,
|
dataProvider: marketInfoWithDataProvider,
|
||||||
skipUpdates: true,
|
skipUpdates: true,
|
||||||
variables: {
|
variables: {
|
||||||
marketId: marketId || '',
|
marketId: marketId || '',
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { Oracle } from './oracles/id';
|
|||||||
import Party from './parties';
|
import Party from './parties';
|
||||||
import { Parties } from './parties/home';
|
import { Parties } from './parties/home';
|
||||||
import { Party as PartySingle } from './parties/id';
|
import { Party as PartySingle } from './parties/id';
|
||||||
import Txs from './txs';
|
|
||||||
import { ValidatorsPage } from './validators';
|
import { ValidatorsPage } from './validators';
|
||||||
import Genesis from './genesis';
|
import Genesis from './genesis';
|
||||||
import { Block } from './blocks/id';
|
import { Block } from './blocks/id';
|
||||||
@@ -20,23 +19,55 @@ import flags from '../config/flags';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
import { NetworkParameters } from './network-parameters';
|
import { NetworkParameters } from './network-parameters';
|
||||||
import type { RouteObject } from 'react-router-dom';
|
import type { Params, RouteObject } from 'react-router-dom';
|
||||||
|
import { createBrowserRouter } from 'react-router-dom';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import { MarketPage, MarketsPage } from './markets';
|
import { MarketPage, MarketsPage } from './markets';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import { ErrorBoundary, Layout } from './layout';
|
||||||
|
import compact from 'lodash/compact';
|
||||||
|
import { AssetLink, MarketLink } from '../components/links';
|
||||||
|
import { truncateMiddle } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
export type Navigable = {
|
export type Navigable = {
|
||||||
path: string;
|
path: string;
|
||||||
name: string;
|
handle: {
|
||||||
text: string;
|
name: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export const isNavigable = (item: RouteObject): item is Navigable =>
|
||||||
|
(item as Navigable).path !== undefined &&
|
||||||
|
(item as Navigable).handle !== undefined &&
|
||||||
|
(item as Navigable).handle.name !== undefined &&
|
||||||
|
(item as Navigable).handle.text !== undefined;
|
||||||
|
|
||||||
|
export type Breadcrumbable = {
|
||||||
|
handle: { breadcrumb: (data?: Params<string>) => ReactNode | string };
|
||||||
|
};
|
||||||
|
export const isBreadcrumbable = (item: RouteObject): item is Breadcrumbable =>
|
||||||
|
(item as Breadcrumbable).handle !== undefined &&
|
||||||
|
(item as Breadcrumbable).handle.breadcrumb !== undefined;
|
||||||
|
|
||||||
|
type RouteItem =
|
||||||
|
| RouteObject
|
||||||
|
| (RouteObject & Navigable)
|
||||||
|
| (RouteObject & Breadcrumbable);
|
||||||
|
type Route = RouteItem & {
|
||||||
|
children?: RouteItem[];
|
||||||
};
|
};
|
||||||
type Route = RouteObject & Navigable;
|
|
||||||
|
|
||||||
const partiesRoutes: Route[] = flags.parties
|
const partiesRoutes: Route[] = flags.parties
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.PARTIES,
|
path: Routes.PARTIES,
|
||||||
name: t('Parties'),
|
|
||||||
text: t('Parties'),
|
|
||||||
element: <Party />,
|
element: <Party />,
|
||||||
|
handle: {
|
||||||
|
name: t('Parties'),
|
||||||
|
text: t('Parties'),
|
||||||
|
breadcrumb: () => <Link to={Routes.PARTIES}>{t('Parties')}</Link>,
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
@@ -45,6 +76,13 @@ const partiesRoutes: Route[] = flags.parties
|
|||||||
{
|
{
|
||||||
path: ':party',
|
path: ':party',
|
||||||
element: <PartySingle />,
|
element: <PartySingle />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
|
{truncateMiddle(params.party as string)}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -55,8 +93,11 @@ const assetsRoutes: Route[] = flags.assets
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.ASSETS,
|
path: Routes.ASSETS,
|
||||||
text: t('Assets'),
|
handle: {
|
||||||
name: t('Assets'),
|
name: t('Assets'),
|
||||||
|
text: t('Assets'),
|
||||||
|
breadcrumb: () => <Link to={Routes.ASSETS}>{t('Assets')}</Link>,
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
@@ -65,6 +106,11 @@ const assetsRoutes: Route[] = flags.assets
|
|||||||
{
|
{
|
||||||
path: ':assetId',
|
path: ':assetId',
|
||||||
element: <AssetPage />,
|
element: <AssetPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<AssetLink assetId={params.assetId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -75,8 +121,13 @@ const genesisRoutes: Route[] = flags.genesis
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.GENESIS,
|
path: Routes.GENESIS,
|
||||||
name: t('Genesis'),
|
handle: {
|
||||||
text: t('Genesis Parameters'),
|
name: t('Genesis'),
|
||||||
|
text: t('Genesis Parameters'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.GENESIS}>{t('Genesis Parameters')}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
element: <Genesis />,
|
element: <Genesis />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -86,8 +137,13 @@ const governanceRoutes: Route[] = flags.governance
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.GOVERNANCE,
|
path: Routes.GOVERNANCE,
|
||||||
name: t('Governance proposals'),
|
handle: {
|
||||||
text: t('Governance Proposals'),
|
name: t('Governance proposals'),
|
||||||
|
text: t('Governance Proposals'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.GOVERNANCE}>{t('Governance Proposals')}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
element: <Proposals />,
|
element: <Proposals />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -97,8 +153,11 @@ const marketsRoutes: Route[] = flags.markets
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.MARKETS,
|
path: Routes.MARKETS,
|
||||||
name: t('Markets'),
|
handle: {
|
||||||
text: t('Markets'),
|
name: t('Markets'),
|
||||||
|
text: t('Markets'),
|
||||||
|
breadcrumb: () => <Link to={Routes.MARKETS}>{t('Markets')}</Link>,
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
@@ -107,6 +166,11 @@ const marketsRoutes: Route[] = flags.markets
|
|||||||
{
|
{
|
||||||
path: ':marketId',
|
path: ':marketId',
|
||||||
element: <MarketPage />,
|
element: <MarketPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<MarketLink id={params.marketId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -117,8 +181,15 @@ const networkParametersRoutes: Route[] = flags.networkParameters
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.NETWORK_PARAMETERS,
|
path: Routes.NETWORK_PARAMETERS,
|
||||||
name: t('NetworkParameters'),
|
handle: {
|
||||||
text: t('Network Parameters'),
|
name: t('NetworkParameters'),
|
||||||
|
text: t('Network Parameters'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.NETWORK_PARAMETERS}>
|
||||||
|
{t('Network Parameters')}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
element: <NetworkParameters />,
|
element: <NetworkParameters />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -128,80 +199,133 @@ const validators: Route[] = flags.validators
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.VALIDATORS,
|
path: Routes.VALIDATORS,
|
||||||
name: t('Validators'),
|
handle: {
|
||||||
text: t('Validators'),
|
name: t('Validators'),
|
||||||
|
text: t('Validators'),
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={Routes.VALIDATORS}>{t('Validators')}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
element: <ValidatorsPage />,
|
element: <ValidatorsPage />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const routerConfig: Route[] = [
|
const linkTo = (...segments: (string | undefined)[]) =>
|
||||||
|
compact(segments).join('/');
|
||||||
|
|
||||||
|
export const routerConfig: Route[] = [
|
||||||
{
|
{
|
||||||
path: Routes.HOME,
|
path: Routes.HOME,
|
||||||
name: t('Home'),
|
element: <Layout />,
|
||||||
text: t('Home'),
|
handle: {
|
||||||
element: <Home />,
|
name: t('Home'),
|
||||||
index: true,
|
text: t('Home'),
|
||||||
},
|
breadcrumb: () => <Link to={Routes.HOME}>{t('Home')}</Link>,
|
||||||
{
|
},
|
||||||
path: Routes.TX,
|
errorElement: <ErrorBoundary />,
|
||||||
name: t('Txs'),
|
|
||||||
text: t('Transactions'),
|
|
||||||
element: <Txs />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'pending',
|
|
||||||
element: <PendingTxs />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':txHash',
|
|
||||||
element: <Tx />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <TxsList />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: Routes.BLOCKS,
|
|
||||||
name: t('Blocks'),
|
|
||||||
text: t('Blocks'),
|
|
||||||
element: <BlockPage />,
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
element: <Blocks />,
|
element: <Home />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':block',
|
path: Routes.TX,
|
||||||
element: <Block />,
|
handle: {
|
||||||
|
name: t('Txs'),
|
||||||
|
text: t('Transactions'),
|
||||||
|
breadcrumb: () => <Link to={Routes.TX}>{t('Transactions')}</Link>,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'pending',
|
||||||
|
element: <PendingTxs />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: () => (
|
||||||
|
<Link to={linkTo(Routes.TX, 'pending')}>
|
||||||
|
{t('Pending transactions')}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':txHash',
|
||||||
|
element: <Tx />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.TX, params.txHash)}>
|
||||||
|
{truncateMiddle(remove0x(params.txHash as string))}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <TxsList />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: Routes.BLOCKS,
|
||||||
|
handle: {
|
||||||
|
name: t('Blocks'),
|
||||||
|
text: t('Blocks'),
|
||||||
|
breadcrumb: () => <Link to={Routes.BLOCKS}>{t('Blocks')}</Link>,
|
||||||
|
},
|
||||||
|
element: <BlockPage />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <Blocks />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':block',
|
||||||
|
element: <Block />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.BLOCKS, params.block)}>
|
||||||
|
{params.block}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: Routes.ORACLES,
|
||||||
|
handle: {
|
||||||
|
name: t('Oracles'),
|
||||||
|
text: t('Oracles'),
|
||||||
|
breadcrumb: () => <Link to={Routes.ORACLES}>{t('Oracles')}</Link>,
|
||||||
|
},
|
||||||
|
element: <OraclePage />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <Oracles />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':id',
|
||||||
|
element: <Oracle />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<Link to={linkTo(Routes.ORACLES, params.id)}>
|
||||||
|
{truncateMiddle(params.id as string)}
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
...partiesRoutes,
|
||||||
|
...assetsRoutes,
|
||||||
|
...genesisRoutes,
|
||||||
|
...governanceRoutes,
|
||||||
|
...marketsRoutes,
|
||||||
|
...networkParametersRoutes,
|
||||||
|
...validators,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: Routes.ORACLES,
|
|
||||||
name: t('Oracles'),
|
|
||||||
text: t('Oracles'),
|
|
||||||
element: <OraclePage />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
element: <Oracles />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: ':id',
|
|
||||||
element: <Oracle />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
...partiesRoutes,
|
|
||||||
...assetsRoutes,
|
|
||||||
...genesisRoutes,
|
|
||||||
...governanceRoutes,
|
|
||||||
...marketsRoutes,
|
|
||||||
...networkParametersRoutes,
|
|
||||||
...validators,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default routerConfig;
|
export const router = createBrowserRouter(routerConfig);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
|
||||||
import { remove0x } from '@vegaprotocol/utils';
|
import { remove0x } from '@vegaprotocol/utils';
|
||||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||||
import { DATA_SOURCES } from '../../../config';
|
import { DATA_SOURCES } from '../../../config';
|
||||||
@@ -8,9 +7,6 @@ import { TxDetails } from './tx-details';
|
|||||||
import type { BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
|
import type { BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
|
||||||
import { toNonHex } from '../../../components/search/detect-search';
|
import { toNonHex } from '../../../components/search/detect-search';
|
||||||
import { PageHeader } from '../../../components/page-header';
|
import { PageHeader } from '../../../components/page-header';
|
||||||
import { Routes } from '../../../routes/route-names';
|
|
||||||
import { IconNames } from '@blueprintjs/icons';
|
|
||||||
import { Icon } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
|
|
||||||
const Tx = () => {
|
const Tx = () => {
|
||||||
@@ -22,6 +18,7 @@ const Tx = () => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
state: { data, loading, error },
|
state: { data, loading, error },
|
||||||
|
refetch,
|
||||||
} = useFetch<BlockExplorerTransaction>(
|
} = useFetch<BlockExplorerTransaction>(
|
||||||
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
|
`${DATA_SOURCES.blockExplorerUrl}/transactions/${toNonHex(hash)}`
|
||||||
);
|
);
|
||||||
@@ -34,17 +31,6 @@ const Tx = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<Link
|
|
||||||
className="font-normal underline underline-offset-4 block mb-5"
|
|
||||||
to={`/${Routes.TX}`}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
className="text-vega-light-150 dark:text-vega-light-150"
|
|
||||||
name={IconNames.CHEVRON_LEFT}
|
|
||||||
/>
|
|
||||||
All Transactions
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="transaction"
|
title="transaction"
|
||||||
truncateStart={5}
|
truncateStart={5}
|
||||||
@@ -56,6 +42,7 @@ const Tx = () => {
|
|||||||
error={error}
|
error={error}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
|
refetch={refetch}
|
||||||
>
|
>
|
||||||
<TxDetails
|
<TxDetails
|
||||||
className="mb-28"
|
className="mb-28"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
|
|||||||
import { PageTitle } from '../../components/page-helpers/page-title';
|
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {
|
import {
|
||||||
ContractAddressLink,
|
EtherscanLink,
|
||||||
DApp,
|
DApp,
|
||||||
TOKEN_VALIDATOR,
|
TOKEN_VALIDATOR,
|
||||||
useLinks,
|
useLinks,
|
||||||
@@ -224,7 +224,7 @@ export const ValidatorsPage = () => {
|
|||||||
<KeyValueTableRow>
|
<KeyValueTableRow>
|
||||||
<div>{t('Ethereum address')}</div>
|
<div>{t('Ethereum address')}</div>
|
||||||
<div className="break-all text-xs">
|
<div className="break-all text-xs">
|
||||||
<ContractAddressLink address={v.ethereumAddress} />{' '}
|
<EtherscanLink address={v.ethereumAddress} />{' '}
|
||||||
<CopyWithTooltip text={v.ethereumAddress}>
|
<CopyWithTooltip text={v.ethereumAddress}>
|
||||||
<button title={t('Copy address to clipboard')}>
|
<button title={t('Copy address to clipboard')}>
|
||||||
<Icon size={3} name="duplicate" />
|
<Icon size={3} name="duplicate" />
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
import App from './app/app';
|
import App from './app/app';
|
||||||
@@ -10,8 +9,6 @@ const root = rootElement && createRoot(rootElement);
|
|||||||
|
|
||||||
root?.render(
|
root?.render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<BrowserRouter>
|
<App />
|
||||||
<App />
|
|
||||||
</BrowserRouter>
|
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
|
|||||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
|
|
||||||
#Test configuration variables
|
#Test configuration variables
|
||||||
CYPRESS_FAIRGROUND=false
|
CYPRESS_FAIRGROUND=false
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
"changes": {
|
"changes": {
|
||||||
"decimalPlaces": "5",
|
"decimalPlaces": "5",
|
||||||
"positionDecimalPlaces": "5",
|
"positionDecimalPlaces": "5",
|
||||||
|
"linearSlippageFactor": "0.001",
|
||||||
|
"quadraticSlippageFactor": "0",
|
||||||
"lpPriceRange": "10",
|
"lpPriceRange": "10",
|
||||||
"instrument": {
|
"instrument": {
|
||||||
"name": "Token test market",
|
"name": "Token test market",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"lpPriceRange": "10",
|
"lpPriceRange": "10",
|
||||||
|
"linearSlippageFactor": "0.001",
|
||||||
|
"quadraticSlippageFactor": "0",
|
||||||
"instrument": {
|
"instrument": {
|
||||||
"code": "TEST.24h",
|
"code": "TEST.24h",
|
||||||
"future": {
|
"future": {
|
||||||
|
|||||||
+103
-91
@@ -1,9 +1,28 @@
|
|||||||
import { associateTokenStartOfTests } from '../../support/common.functions';
|
|
||||||
import {
|
import {
|
||||||
|
navigateTo,
|
||||||
|
waitForSpinner,
|
||||||
|
navigation,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
convertUnixTimestampToDateformat,
|
||||||
createRawProposal,
|
createRawProposal,
|
||||||
|
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||||
|
enterUniqueFreeFormProposalBody,
|
||||||
generateFreeFormProposalTitle,
|
generateFreeFormProposalTitle,
|
||||||
|
getGovernanceProposalDateFormatForSpecifiedDays,
|
||||||
|
getProposalIdFromList,
|
||||||
|
getProposalInformationFromTable,
|
||||||
|
getSubmittedProposalFromProposalList,
|
||||||
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
} from '../../support/governance.functions';
|
voteForProposal,
|
||||||
|
waitForProposalSubmitted,
|
||||||
|
waitForProposalSync,
|
||||||
|
} from '../../../../governance-e2e/src/support/governance.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } 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 type { testFreeformProposal } from '../../support/common-interfaces';
|
||||||
|
|
||||||
const proposalVoteProgressForPercentage =
|
const proposalVoteProgressForPercentage =
|
||||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||||
@@ -25,24 +44,23 @@ describe(
|
|||||||
function () {
|
function () {
|
||||||
before('connect wallets and set approval limit', function () {
|
before('connect wallets and set approval limit', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
associateTokenStartOfTests();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit proposals tab', function () {
|
beforeEach('visit proposals tab', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(1);
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-055
|
// 3001-VOTE-050 3001-VOTE-054 3001-VOTE-055 3002-PROP-019
|
||||||
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
||||||
createRawProposal();
|
createRawProposal();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_proposal_id_from_list(rawProposal.rationale.title);
|
getProposalIdFromList(rawProposal.rationale.title);
|
||||||
cy.get('@proposalIdText').then((proposalId) => {
|
cy.get('@proposalIdText').then((proposalId) => {
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.get(`#${proposalId}`).within(() => {
|
cy.get(`#${proposalId}`).within(() => {
|
||||||
@@ -69,30 +87,26 @@ describe(
|
|||||||
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
||||||
const closingVoteHrs = '72';
|
const closingVoteHrs = '72';
|
||||||
const proposalTitle = generateFreeFormProposalTitle();
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
|
const proposalTimeStamp = createTenDigitUnixTimeStampForSpecifiedDays(3);
|
||||||
|
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('3').then(
|
enterUniqueFreeFormProposalBody(closingVoteHrs, proposalTitle);
|
||||||
(closingDateTimestamp) => {
|
waitForProposalSubmitted();
|
||||||
cy.enter_unique_freeform_proposal_body(closingVoteHrs, proposalTitle);
|
waitForProposalSync();
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
cy.wait_for_proposal_submitted();
|
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
|
||||||
cy.wait_for_proposal_sync();
|
cy.get(viewProposalButton).click()
|
||||||
cy.navigate_to('proposals');
|
);
|
||||||
cy.get_submitted_proposal_from_proposal_list(proposalTitle).within(
|
convertUnixTimestampToDateformat(proposalTimeStamp).then(
|
||||||
() => cy.get(viewProposalButton).click()
|
(closingDate) => {
|
||||||
);
|
getProposalInformationFromTable('Closes on')
|
||||||
cy.convert_unix_timestamp_to_governance_data_table_date_format(
|
.contains(closingDate)
|
||||||
closingDateTimestamp
|
.should('be.visible');
|
||||||
).then((closingDate) => {
|
|
||||||
cy.get_proposal_information_from_table('Closes on')
|
|
||||||
.contains(closingDate)
|
|
||||||
.should('be.visible');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
cy.get_governance_proposal_date_format_for_specified_days('0').then(
|
getGovernanceProposalDateFormatForSpecifiedDays(0).then(
|
||||||
(proposalDate) => {
|
(proposalDate) => {
|
||||||
cy.get_proposal_information_from_table('Proposed on')
|
getProposalInformationFromTable('Proposed on')
|
||||||
.contains(proposalDate)
|
.contains(proposalDate)
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
}
|
}
|
||||||
@@ -104,25 +118,25 @@ describe(
|
|||||||
// 3001-VOTE-040
|
// 3001-VOTE-040
|
||||||
// 3001-VOTE-067
|
// 3001-VOTE-067
|
||||||
createRawProposal();
|
createRawProposal();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(
|
||||||
rawProposal.rationale.title
|
rawProposal.rationale.title
|
||||||
).within(() => cy.get(viewProposalButton).click());
|
).within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
|
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
|
||||||
'be.visible'
|
'be.visible'
|
||||||
);
|
);
|
||||||
cy.get_proposal_information_from_table('Expected to pass')
|
getProposalInformationFromTable('Expected to pass')
|
||||||
.contains('👎')
|
.contains('👎')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
// 3001-VOTE-062
|
// 3001-VOTE-062
|
||||||
// 3001-VOTE-040
|
// 3001-VOTE-040
|
||||||
// 3001-VOTE-070
|
// 3001-VOTE-070
|
||||||
cy.get_proposal_information_from_table('Token majority met')
|
getProposalInformationFromTable('Token majority met')
|
||||||
.contains('👎')
|
.contains('👎')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
// 3001-VOTE-068
|
// 3001-VOTE-068
|
||||||
cy.get_proposal_information_from_table('Token participation met')
|
getProposalInformationFromTable('Token participation met')
|
||||||
.contains('👎')
|
.contains('👎')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
});
|
});
|
||||||
@@ -130,28 +144,27 @@ describe(
|
|||||||
// 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073
|
// 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073
|
||||||
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
|
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
|
||||||
createRawProposal();
|
createRawProposal();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(
|
||||||
rawProposal.rationale.title
|
rawProposal.rationale.title
|
||||||
).within(() => cy.get(viewProposalButton).click());
|
).within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
// 3001-VOTE-080
|
// 3001-VOTE-080
|
||||||
cy.getByTestId('vote-buttons').contains('against').should('be.visible');
|
cy.getByTestId('vote-buttons').contains('against').should('be.visible');
|
||||||
cy.getByTestId('vote-buttons').contains('for').should('be.visible');
|
cy.getByTestId('vote-buttons').contains('for').should('be.visible');
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
cy.get_governance_proposal_date_format_for_specified_days(
|
getGovernanceProposalDateFormatForSpecifiedDays(0, 'shortMonth').then(
|
||||||
'0',
|
(votedDate) => {
|
||||||
'shortMonth'
|
// 3001-VOTE-051
|
||||||
).then((votedDate) => {
|
// 3001-VOTE-093
|
||||||
// 3001-VOTE-051
|
cy.contains('You voted:')
|
||||||
// 3001-VOTE-093
|
.siblings()
|
||||||
cy.contains('You voted:')
|
.contains('For')
|
||||||
.siblings()
|
.siblings()
|
||||||
.contains('For')
|
.contains(votedDate)
|
||||||
.siblings()
|
.should('be.visible');
|
||||||
.contains(votedDate)
|
}
|
||||||
.should('be.visible');
|
);
|
||||||
});
|
|
||||||
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||||
.contains('100.00%')
|
.contains('100.00%')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
@@ -162,38 +175,38 @@ describe(
|
|||||||
cy.get(proposalVoteProgressAgainstTokens)
|
cy.get(proposalVoteProgressAgainstTokens)
|
||||||
.contains('0.00')
|
.contains('0.00')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
getProposalInformationFromTable('Tokens for proposal')
|
||||||
.should('have.text', parseFloat(1).toFixed(2))
|
.should('have.text', (1).toFixed(2))
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens against proposal')
|
getProposalInformationFromTable('Tokens against proposal')
|
||||||
.should('have.text', '0.00')
|
.should('have.text', '0.00')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
// 3001-VOTE-061
|
// 3001-VOTE-061
|
||||||
cy.get_proposal_information_from_table('Participation required')
|
getProposalInformationFromTable('Participation required')
|
||||||
.contains(0.001)
|
.contains('0.00%')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
// 3001-VOTE-066
|
// 3001-VOTE-066
|
||||||
cy.get_proposal_information_from_table('Majority Required') // 3001-VOTE-073
|
getProposalInformationFromTable('Majority Required') // 3001-VOTE-073
|
||||||
.contains(`${parseFloat(100).toFixed(2)}%`)
|
.contains(`${(66).toFixed(2)}%`)
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
cy.get_proposal_information_from_table('Number of voting parties')
|
getProposalInformationFromTable('Number of voting parties')
|
||||||
.should('have.text', '1')
|
.should('have.text', '1')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get(changeVoteButton).should('be.visible').click();
|
cy.get(changeVoteButton).should('be.visible').click();
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
// 3001-VOTE-064
|
// 3001-VOTE-064
|
||||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
getProposalInformationFromTable('Tokens for proposal')
|
||||||
.should('have.text', parseFloat(1).toFixed(2))
|
.should('have.text', (1).toFixed(2))
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get(changeVoteButton).should('be.visible').click();
|
cy.get(changeVoteButton).should('be.visible').click();
|
||||||
cy.vote_for_proposal('against');
|
voteForProposal('against');
|
||||||
cy.get(proposalVoteProgressAgainstPercentage)
|
cy.get(proposalVoteProgressAgainstPercentage)
|
||||||
.contains('100.00%')
|
.contains('100.00%')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens against proposal')
|
getProposalInformationFromTable('Tokens against proposal')
|
||||||
.should('have.text', parseFloat(1).toFixed(2))
|
.should('have.text', (1).toFixed(2))
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Number of voting parties')
|
getProposalInformationFromTable('Number of voting parties')
|
||||||
.should('have.text', '1')
|
.should('have.text', '1')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
@@ -201,30 +214,31 @@ describe(
|
|||||||
// 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060
|
// 3001-VOTE-042, 3001-VOTE-057, 3001-VOTE-058, 3001-VOTE-059, 3001-VOTE-060
|
||||||
it('Newly created proposal details - ability to increase associated tokens - by voting again after association', function () {
|
it('Newly created proposal details - ability to increase associated tokens - by voting again after association', function () {
|
||||||
createRawProposal();
|
createRawProposal();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(rawProposal.rationale.title)
|
||||||
rawProposal.rationale.title
|
|
||||||
)
|
|
||||||
.as('submittedProposal')
|
.as('submittedProposal')
|
||||||
.within(() => cy.get(viewProposalButton).click());
|
.within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
// 3001-VOTE-079
|
// 3001-VOTE-079
|
||||||
cy.contains('You voted: For').should('be.visible');
|
cy.contains('You voted: For').should('be.visible');
|
||||||
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
|
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Total Supply')
|
getProposalInformationFromTable('Total Supply')
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.then((totalSupply) => {
|
.then((totalSupply) => {
|
||||||
let tokensRequiredToAchieveResult = parseFloat(
|
const tokensRequiredToAchieveResult = (
|
||||||
(totalSupply.replace(/,/g, '') * 0.001) / 100
|
(Number(totalSupply.replace(/,/g, '')) * 0.001) /
|
||||||
|
100
|
||||||
).toFixed(2);
|
).toFixed(2);
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
ensureSpecifiedUnstakedTokensAreAssociated(
|
||||||
tokensRequiredToAchieveResult
|
tokensRequiredToAchieveResult
|
||||||
);
|
);
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.get('@submittedProposal').within(() =>
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get(viewProposalButton).click()
|
getSubmittedProposalFromProposalList(rawProposal.rationale.title)
|
||||||
);
|
.as('submittedProposal')
|
||||||
|
.within(() => cy.get(viewProposalButton).click());
|
||||||
|
});
|
||||||
cy.get(proposalVoteProgressForPercentage)
|
cy.get(proposalVoteProgressForPercentage)
|
||||||
.contains('100.00%')
|
.contains('100.00%')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
@@ -233,38 +247,36 @@ describe(
|
|||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
// 3001-VOTE-065
|
// 3001-VOTE-065
|
||||||
cy.get(changeVoteButton).should('be.visible').click();
|
cy.get(changeVoteButton).should('be.visible').click();
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
cy.get(proposalVoteProgressForTokens)
|
cy.get(proposalVoteProgressForTokens)
|
||||||
.contains(tokensRequiredToAchieveResult)
|
.contains(tokensRequiredToAchieveResult)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get(proposalVoteProgressAgainstTokens)
|
cy.get(proposalVoteProgressAgainstTokens)
|
||||||
.contains('0.00')
|
.contains('0.00')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table(
|
getProposalInformationFromTable('Total tokens voted percentage')
|
||||||
'Total tokens voted percentage'
|
|
||||||
)
|
|
||||||
.should('have.text', '0.00%')
|
.should('have.text', '0.00%')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
getProposalInformationFromTable('Tokens for proposal')
|
||||||
.should('have.text', tokensRequiredToAchieveResult)
|
.should('have.text', tokensRequiredToAchieveResult)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens against proposal')
|
getProposalInformationFromTable('Tokens against proposal')
|
||||||
.should('have.text', '0.00')
|
.should('have.text', '0.00')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Number of voting parties')
|
getProposalInformationFromTable('Number of voting parties')
|
||||||
.should('have.text', '1')
|
.should('have.text', '1')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Expected to pass')
|
getProposalInformationFromTable('Expected to pass')
|
||||||
.contains('👍')
|
.contains('👍')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
// 3001-VOTE-062
|
// 3001-VOTE-062
|
||||||
cy.get_proposal_information_from_table('Token majority met')
|
getProposalInformationFromTable('Token majority met')
|
||||||
.contains('👍')
|
.contains('👍')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
cy.get_proposal_information_from_table('Token participation met')
|
getProposalInformationFromTable('Token participation met')
|
||||||
.contains('👍')
|
.contains('👍')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
getProposalInformationFromTable('Tokens for proposal')
|
||||||
.contains(tokensRequiredToAchieveResult)
|
.contains(tokensRequiredToAchieveResult)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
+37
-27
@@ -1,10 +1,21 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
import { associateTokenStartOfTests } from '../../support/governance.functions';
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
getProposalInformationFromTable,
|
||||||
|
voteForProposal,
|
||||||
|
} from '../../support/governance.functions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createUpdateNetworkProposalTxBody,
|
createUpdateNetworkProposalTxBody,
|
||||||
createFreeFormProposalTxBody,
|
createFreeFormProposalTxBody,
|
||||||
} from '../../support/proposal.functions';
|
} from '../../support/proposal.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||||
|
|
||||||
const closedProposals = '[data-testid="closed-proposals"]';
|
const closedProposals = '[data-testid="closed-proposals"]';
|
||||||
const proposalStatus = '[data-testid="proposal-status"]';
|
const proposalStatus = '[data-testid="proposal-status"]';
|
||||||
@@ -21,20 +32,19 @@ context(
|
|||||||
function () {
|
function () {
|
||||||
before('Connect wallets and set approval', function () {
|
before('Connect wallets and set approval', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
associateTokenStartOfTests();
|
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(1);
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
cy.clearLocalStorage();
|
cy.clearLocalStorage();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit proposals', function () {
|
beforeEach('visit proposals', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-006
|
// 3001-VOTE-006
|
||||||
@@ -43,7 +53,7 @@ context(
|
|||||||
|
|
||||||
cy.createMarket();
|
cy.createMarket();
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.get(closedProposals).within(() => {
|
cy.get(closedProposals).within(() => {
|
||||||
cy.contains(proposalTitle)
|
cy.contains(proposalTitle)
|
||||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||||
@@ -53,7 +63,7 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Enacted')
|
.contains('Enacted')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get(votesTable).within(() => {
|
cy.get(votesTable).within(() => {
|
||||||
@@ -68,22 +78,22 @@ context(
|
|||||||
const proposalTx = createUpdateNetworkProposalTxBody();
|
const proposalTx = createUpdateNetworkProposalTxBody();
|
||||||
|
|
||||||
cy.VegaWalletSubmitProposal(proposalTx);
|
cy.VegaWalletSubmitProposal(proposalTx);
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.contains(proposalTitle)
|
cy.contains(proposalTitle)
|
||||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||||
.within(() => cy.get(viewProposalButton).click());
|
.within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Open')
|
.contains('Open')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
getProposalInformationFromTable('State') // 3001-VOTE-047
|
||||||
.contains('Passed', proposalTimeout)
|
.contains('Passed', proposalTimeout)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Enacted', proposalTimeout)
|
.contains('Enacted', proposalTimeout)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get(votesTable).within(() => {
|
cy.get(votesTable).within(() => {
|
||||||
@@ -101,43 +111,43 @@ context(
|
|||||||
const proposalTx = createFreeFormProposalTxBody();
|
const proposalTx = createFreeFormProposalTxBody();
|
||||||
|
|
||||||
cy.VegaWalletSubmitProposal(proposalTx);
|
cy.VegaWalletSubmitProposal(proposalTx);
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.contains(proposalTitle)
|
cy.contains(proposalTitle)
|
||||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||||
.within(() => cy.get(viewProposalButton).click());
|
.within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Open')
|
.contains('Open')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Enacted', proposalTimeout)
|
.contains('Enacted', proposalTimeout)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-048 3001-VOTE-049
|
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
|
||||||
it('Able to fail proposal due to lack of participation', function () {
|
it('Able to fail proposal due to lack of participation', function () {
|
||||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||||
const proposalTx = createFreeFormProposalTxBody();
|
const proposalTx = createFreeFormProposalTxBody();
|
||||||
cy.VegaWalletSubmitProposal(proposalTx);
|
cy.VegaWalletSubmitProposal(proposalTx);
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.contains(proposalTitle)
|
cy.contains(proposalTitle)
|
||||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||||
.within(() => cy.get(viewProposalButton).click());
|
.within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Open')
|
.contains('Open')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
getProposalInformationFromTable('State') // 3001-VOTE-047
|
||||||
.contains('Declined', proposalTimeout)
|
.contains('Declined', proposalTimeout)
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Rejection reason')
|
getProposalInformationFromTable('Rejection reason')
|
||||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
+146
-151
@@ -1,22 +1,47 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
import {
|
import {
|
||||||
createRawProposal,
|
createRawProposal,
|
||||||
|
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||||
|
enterRawProposalBody,
|
||||||
|
enterUniqueFreeFormProposalBody,
|
||||||
generateFreeFormProposalTitle,
|
generateFreeFormProposalTitle,
|
||||||
|
getProposalInformationFromTable,
|
||||||
|
getSubmittedProposalFromProposalList,
|
||||||
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
|
voteForProposal,
|
||||||
|
waitForProposalSubmitted,
|
||||||
|
waitForProposalSync,
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
|
|
||||||
import { associateTokenStartOfTests } from '../../support/common.functions';
|
import {
|
||||||
|
verifyUnstakedBalance,
|
||||||
|
waitForSpinner,
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
closeDialog,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
clickOnValidatorFromList,
|
||||||
|
closeStakingDialog,
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated,
|
||||||
|
stakingPageDisassociateTokens,
|
||||||
|
stakingValidatorPageAddStake,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
|
import {
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||||
|
|
||||||
const vegaWalletUnstakedBalance =
|
|
||||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
|
||||||
const vegaWalletStakedBalances =
|
const vegaWalletStakedBalances =
|
||||||
'[data-testid="vega-wallet-balance-staked-validators"]';
|
'[data-testid="vega-wallet-balance-staked-validators"]';
|
||||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
|
||||||
const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
const vegaWalletNameElement = '[data-testid="wallet-name"]';
|
||||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
const vegaWallet = '[data-testid="vega-wallet"]';
|
||||||
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
|
||||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||||
const rawProposalData = '[data-testid="proposal-data"]';
|
const rawProposalData = '[data-testid="proposal-data"]';
|
||||||
const minVoteButton = '[data-testid="min-vote"]';
|
const minVoteButton = '[data-testid="min-vote"]';
|
||||||
@@ -40,30 +65,31 @@ context(
|
|||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
network_parameters['spam.protection.proposal.min.tokens'] /
|
Number(network_parameters['spam.protection.proposal.min.tokens']) /
|
||||||
1000000000000000000
|
1000000000000000000
|
||||||
).as('minProposerBalance');
|
).as('minProposerBalance');
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
network_parameters['spam.protection.voting.min.tokens'] /
|
Number(network_parameters['spam.protection.voting.min.tokens']) /
|
||||||
1000000000000000000
|
1000000000000000000
|
||||||
).as('minVoterBalance');
|
).as('minVoterBalance');
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
network_parameters['governance.proposal.freeform.requiredMajority'] *
|
Number(
|
||||||
100
|
network_parameters['governance.proposal.freeform.requiredMajority']
|
||||||
|
) * 100
|
||||||
).as('requiredMajority');
|
).as('requiredMajority');
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
associateTokenStartOfTests();
|
cy.associateTokensToVegaWallet('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit governance tab', function () {
|
beforeEach('visit governance tab', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(1);
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to see that no proposals exist', function () {
|
it('Should be able to see that no proposals exist', function () {
|
||||||
@@ -80,7 +106,7 @@ context(
|
|||||||
// 3002-PROP-003
|
// 3002-PROP-003
|
||||||
it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () {
|
it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () {
|
||||||
// 3002-PROP-005
|
// 3002-PROP-005
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.contains(
|
cy.contains(
|
||||||
`You must have at least 1 VEGA associated to make a proposal`
|
`You must have at least 1 VEGA associated to make a proposal`
|
||||||
).should('be.visible');
|
).should('be.visible');
|
||||||
@@ -88,7 +114,7 @@ context(
|
|||||||
|
|
||||||
// 3002-PROP-011
|
// 3002-PROP-011
|
||||||
it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
it('Able to submit a valid freeform proposal - with minimum required tokens associated', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008
|
cy.get(minVoteButton).should('be.visible'); // 3002-PROP-008
|
||||||
cy.get(maxVoteButton).should('be.visible');
|
cy.get(maxVoteButton).should('be.visible');
|
||||||
cy.get(votingDate).should('not.be.empty');
|
cy.get(votingDate).should('not.be.empty');
|
||||||
@@ -96,40 +122,31 @@ context(
|
|||||||
'contain.text',
|
'contain.text',
|
||||||
'we add 2 minutes of extra time'
|
'we add 2 minutes of extra time'
|
||||||
);
|
);
|
||||||
cy.enter_unique_freeform_proposal_body(
|
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
|
||||||
'50',
|
|
||||||
generateFreeFormProposalTitle()
|
|
||||||
);
|
|
||||||
// 3002-PROP-012
|
// 3002-PROP-012
|
||||||
// 3002-PROP-016
|
// 3002-PROP-016
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () {
|
it('Able to submit a valid freeform proposal - with minimum required tokens associated - but also staked', function () {
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated('2');
|
ensureSpecifiedUnstakedTokensAreAssociated('2');
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', '2');
|
verifyUnstakedBalance(2);
|
||||||
cy.navigate_to('validators');
|
navigateTo(navigation.validators);
|
||||||
cy.click_on_validator_from_list(0);
|
clickOnValidatorFromList(0);
|
||||||
cy.staking_validator_page_add_stake('2');
|
stakingValidatorPageAddStake('2');
|
||||||
cy.close_staking_dialog();
|
closeStakingDialog();
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||||
|
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.enter_unique_freeform_proposal_body(
|
enterUniqueFreeFormProposalBody('50', generateFreeFormProposalTitle());
|
||||||
'50',
|
waitForProposalSubmitted();
|
||||||
generateFreeFormProposalTitle()
|
|
||||||
);
|
|
||||||
cy.wait_for_proposal_submitted();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('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 () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.enter_unique_freeform_proposal_body(
|
enterUniqueFreeFormProposalBody('0.1', generateFreeFormProposalTitle());
|
||||||
'0.1',
|
|
||||||
generateFreeFormProposalTitle()
|
|
||||||
);
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
||||||
'not.exist'
|
'not.exist'
|
||||||
);
|
);
|
||||||
@@ -139,8 +156,8 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('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 () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.enter_unique_freeform_proposal_body(
|
enterUniqueFreeFormProposalBody(
|
||||||
'100000',
|
'100000',
|
||||||
generateFreeFormProposalTitle()
|
generateFreeFormProposalTitle()
|
||||||
);
|
);
|
||||||
@@ -154,22 +171,18 @@ context(
|
|||||||
|
|
||||||
// 3001-VOTE-006
|
// 3001-VOTE-006
|
||||||
it('Creating a proposal - proposal rejected - able to access rejected proposals', function () {
|
it('Creating a proposal - proposal rejected - able to access rejected proposals', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('1000').then(
|
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(1000));
|
||||||
(closingDateTimestamp) => {
|
|
||||||
cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
||||||
'be.visible'
|
'be.visible'
|
||||||
);
|
);
|
||||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||||
cy.get(dialogCloseButton).click();
|
closeDialog();
|
||||||
cy.wait_for_proposal_sync();
|
waitForProposalSync();
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.get(rejectProposalsLink).click();
|
cy.get(rejectProposalsLink).click();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(
|
||||||
rawProposal.rationale.title
|
rawProposal.rationale.title
|
||||||
).within(() => {
|
).within(() => {
|
||||||
cy.contains('Rejected').should('be.visible');
|
cy.contains('Rejected').should('be.visible');
|
||||||
@@ -177,79 +190,68 @@ context(
|
|||||||
cy.get(viewProposalButton).click();
|
cy.get(viewProposalButton).click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Rejected')
|
.contains('Rejected')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Rejection reason')
|
getProposalInformationFromTable('Rejection reason')
|
||||||
.contains('PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE')
|
.contains('PROPOSAL_ERROR_CLOSE_TIME_TOO_LATE')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Error details')
|
getProposalInformationFromTable('Error details')
|
||||||
.contains('proposal closing time too late')
|
.contains('proposal closing time too late')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0005-ETXN-004
|
// 0005-ETXN-004
|
||||||
it('Unable to create a proposal - when no tokens are associated', function () {
|
it('Unable to create a proposal - when no tokens are associated', function () {
|
||||||
cy.vega_wallet_teardown();
|
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.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||||
'0.00',
|
'0.00',
|
||||||
txTimeout
|
txTimeout
|
||||||
);
|
);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
|
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||||
(closingDateTimestamp) => {
|
|
||||||
cy.enter_raw_proposal_body(closingDateTimestamp).as;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
cy.get(feedbackError).should('have.text', errorMsg);
|
||||||
'have.text',
|
closeDialog();
|
||||||
'Network error: the network blocked the transaction through the spam protection'
|
|
||||||
);
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3002-PROP-009
|
// 3002-PROP-009
|
||||||
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
|
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(0.000001);
|
const errorMsg =
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
'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)';
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
|
|
||||||
(closingDateTimestamp) => {
|
ensureSpecifiedUnstakedTokensAreAssociated('0.000001');
|
||||||
cy.enter_raw_proposal_body(closingDateTimestamp);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
}
|
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||||
);
|
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
cy.get(feedbackError).should('have.text', errorMsg);
|
||||||
'have.text',
|
closeDialog();
|
||||||
'Network error: the network blocked the transaction through the spam protection'
|
|
||||||
);
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
|
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
|
||||||
|
const errorMsg =
|
||||||
|
'Invalid params: the transaction does not use a valid Vega command: unknown field unexpected" in vega.commands.v1.ProposalSubmission';
|
||||||
|
|
||||||
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
|
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
|
|
||||||
(closingDateTimestamp) => {
|
cy.fixture('/proposals/raw.json').then((freeformProposal) => {
|
||||||
cy.fixture('/proposals/raw.json').then((freeformProposal) => {
|
freeformProposal.terms.closingTimestamp =
|
||||||
freeformProposal.terms.closingTimestamp = closingDateTimestamp;
|
createTenDigitUnixTimeStampForSpecifiedDays(8);
|
||||||
freeformProposal.unexpected = `i shouldn't be here`;
|
freeformProposal.unexpected = `i shouldn't be here`;
|
||||||
let proposalPayload = JSON.stringify(freeformProposal);
|
const proposalPayload = JSON.stringify(freeformProposal);
|
||||||
cy.get(rawProposalData).type(proposalPayload, {
|
cy.get(rawProposalData).type(proposalPayload, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
|
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
cy.get(feedbackError).should('have.text', errorMsg);
|
||||||
'have.text',
|
closeDialog();
|
||||||
'Invalid params: the transaction is malformed'
|
|
||||||
);
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
cy.get(rawProposalData)
|
cy.get(rawProposalData)
|
||||||
.invoke('val')
|
.invoke('val')
|
||||||
.should('contain', "i shouldn't be here");
|
.should('contain', "i shouldn't be here");
|
||||||
@@ -257,71 +259,64 @@ context(
|
|||||||
|
|
||||||
it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () {
|
it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () {
|
||||||
// 3001-VOTE-038
|
// 3001-VOTE-038
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
const errorMsg =
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
|
'Invalid params: the transaction does not use a valid Vega command: unknown field "unexpectedField" in vega.ProposalTerms';
|
||||||
(closingDateTimestamp) => {
|
|
||||||
cy.fixture('/proposals/raw.json').then((rawProposal) => {
|
|
||||||
rawProposal.terms.closingTimestamp = closingDateTimestamp;
|
|
||||||
rawProposal.terms.unexpectedField = `i shouldn't be here`;
|
|
||||||
let proposalPayload = JSON.stringify(rawProposal);
|
|
||||||
|
|
||||||
cy.get(rawProposalData).type(proposalPayload, {
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
parseSpecialCharSequences: false,
|
|
||||||
delay: 2,
|
cy.fixture('/proposals/raw.json').then((rawProposal) => {
|
||||||
});
|
rawProposal.terms.closingTimestamp =
|
||||||
});
|
createTenDigitUnixTimeStampForSpecifiedDays(8);
|
||||||
}
|
rawProposal.terms.unexpectedField = `i shouldn't be here`;
|
||||||
);
|
const proposalPayload = JSON.stringify(rawProposal);
|
||||||
|
|
||||||
|
cy.get(rawProposalData).type(proposalPayload, {
|
||||||
|
parseSpecialCharSequences: false,
|
||||||
|
delay: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
|
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
cy.get(feedbackError).should('have.text', errorMsg);
|
||||||
'have.text',
|
closeDialog();
|
||||||
'Invalid params: the transaction is malformed'
|
|
||||||
);
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1005-PROP-009
|
// 1005-PROP-009
|
||||||
it.skip(
|
it('Unable to vote on a freeform proposal - when some but not enough vega associated', function () {
|
||||||
'Unable to vote on a freeform proposal - when some but not enough vega associated',
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
{ tags: '@smoke' },
|
|
||||||
function () {
|
|
||||||
const proposalTitle = generateFreeFormProposalTitle();
|
|
||||||
|
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(1);
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
cy.enter_unique_freeform_proposal_body('50', proposalTitle);
|
enterUniqueFreeFormProposalBody('50', proposalTitle);
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
cy.staking_page_disassociate_tokens('0.0001');
|
stakingPageDisassociateTokens('0.0001');
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance).should('have.length', 1);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
'contain',
|
||||||
'contain',
|
'0.9999'
|
||||||
'0.9999'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
cy.navigate_to('proposals');
|
|
||||||
cy.get_submitted_proposal_from_proposal_list(proposalTitle).within(() =>
|
|
||||||
cy.get(viewProposalButton).click()
|
|
||||||
);
|
);
|
||||||
cy.contains('Vote breakdown').should('be.visible', {
|
});
|
||||||
timeout: 10000,
|
navigateTo(navigation.proposals);
|
||||||
});
|
getSubmittedProposalFromProposalList(proposalTitle).within(() =>
|
||||||
cy.get(voteButtons).should('not.exist');
|
cy.get(viewProposalButton).click()
|
||||||
cy.getByTestId('min-proposal-requirements').should(
|
);
|
||||||
'have.text',
|
cy.contains('Vote breakdown').should('be.visible', {
|
||||||
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
|
timeout: 10000,
|
||||||
);
|
});
|
||||||
}
|
cy.get(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`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () {
|
it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () {
|
||||||
createRawProposal();
|
createRawProposal();
|
||||||
cy.get('[data-testid="manage-vega-wallet"]').click();
|
cy.get('[data-testid="manage-vega-wallet"]').click();
|
||||||
cy.get('[data-testid="disconnect"]').click();
|
cy.get('[data-testid="disconnect"]').click();
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(
|
||||||
rawProposal.rationale.title
|
rawProposal.rationale.title
|
||||||
).within(() => cy.get(viewProposalButton).click());
|
).within(() => cy.get(viewProposalButton).click());
|
||||||
});
|
});
|
||||||
@@ -339,7 +334,7 @@ context(
|
|||||||
'1.00',
|
'1.00',
|
||||||
txTimeout
|
txTimeout
|
||||||
);
|
);
|
||||||
cy.vote_for_proposal('against');
|
voteForProposal('against');
|
||||||
// 3001-VOTE-079
|
// 3001-VOTE-079
|
||||||
cy.contains('You voted: Against').should('be.visible');
|
cy.contains('You voted: Against').should('be.visible');
|
||||||
});
|
});
|
||||||
+94
-56
@@ -1,3 +1,23 @@
|
|||||||
|
import {
|
||||||
|
closeDialog,
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
getProposalInformationFromTable,
|
||||||
|
goToMakeNewProposal,
|
||||||
|
voteForProposal,
|
||||||
|
waitForProposalSubmitted,
|
||||||
|
} from '../../support/governance.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import {
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||||
|
|
||||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||||
const openProposals = '[data-testid="open-proposals"]';
|
const openProposals = '[data-testid="open-proposals"]';
|
||||||
const proposalType = '[data-testid="proposal-type"]';
|
const proposalType = '[data-testid="proposal-type"]';
|
||||||
@@ -20,7 +40,6 @@ const maxVoteDeadline = '[data-testid="max-vote"]';
|
|||||||
const minValidationDeadline = '[data-testid="min-validation"]';
|
const minValidationDeadline = '[data-testid="min-validation"]';
|
||||||
const minEnactDeadline = '[data-testid="min-enactment"]';
|
const minEnactDeadline = '[data-testid="min-enactment"]';
|
||||||
const maxEnactDeadline = '[data-testid="max-enactment"]';
|
const maxEnactDeadline = '[data-testid="max-enactment"]';
|
||||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
|
||||||
const inputError = '[data-testid="input-error-text"]';
|
const inputError = '[data-testid="input-error-text"]';
|
||||||
const enactmentDeadlineError =
|
const enactmentDeadlineError =
|
||||||
'[data-testid="enactment-before-voting-deadline"]';
|
'[data-testid="enactment-before-voting-deadline"]';
|
||||||
@@ -29,6 +48,7 @@ const feedbackError = '[data-testid="Error"]';
|
|||||||
const viewProposalBtn = 'view-proposal-btn';
|
const viewProposalBtn = 'view-proposal-btn';
|
||||||
const liquidityVoteStatus = 'liquidity-votes-status';
|
const liquidityVoteStatus = 'liquidity-votes-status';
|
||||||
const tokenVoteStatus = 'token-votes-status';
|
const tokenVoteStatus = 'token-votes-status';
|
||||||
|
const proposalTermsSection = 'proposal';
|
||||||
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
|
||||||
const epochTimeout = Cypress.env('epochTimeout');
|
const epochTimeout = Cypress.env('epochTimeout');
|
||||||
const proposalTimeout = { timeout: 14000 };
|
const proposalTimeout = { timeout: 14000 };
|
||||||
@@ -49,22 +69,22 @@ context(
|
|||||||
{ tags: '@slow' },
|
{ tags: '@slow' },
|
||||||
function () {
|
function () {
|
||||||
before('connect wallets and set approval limit', function () {
|
before('connect wallets and set approval limit', function () {
|
||||||
cy.createMarket();
|
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit governance tab', function () {
|
beforeEach('visit governance tab', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated('1');
|
cy.createMarket();
|
||||||
cy.navigate_to('proposals');
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to submit valid update network parameter proposal', function () {
|
it('Able to submit valid update network parameter proposal', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
// 3002-PROP-006
|
// 3002-PROP-006
|
||||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||||
// 3002-PROP-007
|
// 3002-PROP-007
|
||||||
@@ -78,12 +98,12 @@ context(
|
|||||||
cy.get(currentParameterValue).should('have.value', '2s');
|
cy.get(currentParameterValue).should('have.value', '2s');
|
||||||
cy.get(newProposedParameterValue).type('5s'); // 3007-PNEC-003
|
cy.get(newProposedParameterValue).type('5s'); // 3007-PNEC-003
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit network parameter with missing/invalid fields', function () {
|
it('Unable to submit network parameter with missing/invalid fields', function () {
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type(
|
cy.get(newProposalTitle).type(
|
||||||
@@ -108,7 +128,7 @@ context(
|
|||||||
|
|
||||||
it('Able to download network param proposal json', function () {
|
it('Able to download network param proposal json', function () {
|
||||||
const downloadFolder = './cypress/downloads/';
|
const downloadFolder = './cypress/downloads/';
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
cy.log('Download proposal file');
|
cy.log('Download proposal file');
|
||||||
cy.get(proposalDownloadBtn)
|
cy.get(proposalDownloadBtn)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
@@ -156,8 +176,8 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
|
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
|
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
|
||||||
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
cy.get(newProposalTitle).type('Test update network parameter proposal');
|
||||||
cy.get(newProposalDescription).type('invalid deadlines');
|
cy.get(newProposalDescription).type('invalid deadlines');
|
||||||
cy.get(proposalParameterSelect).select(
|
cy.get(proposalParameterSelect).select(
|
||||||
@@ -175,36 +195,39 @@ context(
|
|||||||
'have.text',
|
'have.text',
|
||||||
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
|
||||||
);
|
);
|
||||||
cy.get(dialogCloseButton).click();
|
closeDialog();
|
||||||
cy.get(minVoteDeadline).click();
|
cy.get(minVoteDeadline).click();
|
||||||
cy.get(enactmentDeadlineError).should('not.exist');
|
cy.get(enactmentDeadlineError).should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3003-PMAN-001
|
// 3003-PMAN-001
|
||||||
it('Able to submit valid new market proposal', function () {
|
it('Able to submit valid new market proposal', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.get(newProposalTitle).type('Test new market proposal');
|
cy.get(newProposalTitle).type('Test new market proposal');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||||
let newMarketPayload = JSON.stringify(newMarketProposal);
|
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit new market proposal with missing/invalid fields', function () {
|
it('Unable to submit new market proposal with missing/invalid fields', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
|
const errorMsg =
|
||||||
|
'Invalid params: the transaction is not a valid Vega command: unknown field "filters" in vega.DataSourceDefinition';
|
||||||
|
|
||||||
|
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type('Test new market proposal');
|
cy.get(newProposalTitle).type('Test new market proposal');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
|
||||||
newMarketProposal.invalid = 'I am an invalid field';
|
newMarketProposal.invalid = 'I am an invalid field';
|
||||||
let newMarketPayload = JSON.stringify(newMarketProposal);
|
const newMarketPayload = JSON.stringify(newMarketProposal);
|
||||||
cy.get(newProposalTerms).type(newMarketPayload, {
|
cy.get(newProposalTerms).type(newMarketPayload, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
@@ -212,21 +235,18 @@ context(
|
|||||||
});
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
|
||||||
cy.get(feedbackError).should(
|
cy.get(feedbackError).should('have.text', errorMsg);
|
||||||
'have.text',
|
|
||||||
'Invalid params: the transaction is not a valid Vega command: unknown field "invalid" in vega.NewMarket'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
// Will fail if run after 'Able to submit update market proposal and vote for proposal'
|
||||||
// 3002-PROP-022
|
// 3002-PROP-022
|
||||||
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
it('Unable to submit update market proposal without equity-like share in the market', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.get(proposalMarketSelect).select('Test market 1');
|
cy.get(proposalMarketSelect).select('Test market 1');
|
||||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||||
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
@@ -237,23 +257,23 @@ context(
|
|||||||
cy.getByTestId('dialog-content')
|
cy.getByTestId('dialog-content')
|
||||||
.find('p')
|
.find('p')
|
||||||
.should('have.text', 'PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
.should('have.text', 'PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated('1');
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3002-PROP-020
|
// 3002-PROP-020
|
||||||
it('Unable to submit update market proposal without minimum amount of tokens', function () {
|
it('Unable to submit update market proposal without minimum amount of tokens', function () {
|
||||||
cy.vega_wallet_teardown();
|
vegaWalletTeardown();
|
||||||
cy.vega_wallet_faucet_assets_without_check(
|
vegaWalletFaucetAssetsWithoutCheck(
|
||||||
'fUSDC',
|
'fUSDC',
|
||||||
'1000000',
|
'1000000',
|
||||||
vegaWalletPublicKey
|
vegaWalletPublicKey
|
||||||
);
|
);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
cy.get(newProposalTitle).type('Test update market proposal - rejected');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.get(proposalMarketSelect).select('Test market 1');
|
cy.get(proposalMarketSelect).select('Test market 1');
|
||||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||||
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
@@ -267,14 +287,14 @@ context(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-092
|
// 3001-VOTE-092 3004-PMAC-001
|
||||||
it('Able to submit update market proposal and vote for proposal', function () {
|
it('Able to submit update market proposal and vote for proposal', function () {
|
||||||
cy.vega_wallet_faucet_assets_without_check(
|
vegaWalletFaucetAssetsWithoutCheck(
|
||||||
'fUSDC',
|
'fUSDC',
|
||||||
'1000000',
|
'1000000',
|
||||||
vegaWalletPublicKey
|
vegaWalletPublicKey
|
||||||
);
|
);
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
|
||||||
cy.get(newProposalTitle).type('Test update market proposal');
|
cy.get(newProposalTitle).type('Test update market proposal');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.get(proposalMarketSelect).select('Test market 1');
|
cy.get(proposalMarketSelect).select('Test market 1');
|
||||||
@@ -285,20 +305,20 @@ context(
|
|||||||
cy.get('dd').eq(2).invoke('text').as('EnactedMarketId');
|
cy.get('dd').eq(2).invoke('text').as('EnactedMarketId');
|
||||||
});
|
});
|
||||||
cy.get('@EnactedMarketId').then((marketId) => {
|
cy.get('@EnactedMarketId').then((marketId) => {
|
||||||
cy.VegaWalletSubmitLiquidityProvision(marketId, '1');
|
cy.VegaWalletSubmitLiquidityProvision(String(marketId), '1');
|
||||||
});
|
});
|
||||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||||
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||||
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.get('@EnactedMarketId').then((marketId) => {
|
cy.get('@EnactedMarketId').then((marketId) => {
|
||||||
cy.contains(marketId)
|
cy.contains(String(marketId))
|
||||||
.parentsUntil(proposalListItem)
|
.parentsUntil(proposalListItem)
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId(viewProposalBtn).click();
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
@@ -312,7 +332,7 @@ context(
|
|||||||
'contain.text',
|
'contain.text',
|
||||||
'Currently expected to fail'
|
'Currently expected to fail'
|
||||||
);
|
);
|
||||||
cy.vote_for_proposal('for');
|
voteForProposal('for');
|
||||||
cy.getByTestId(liquidityVoteStatus).should(
|
cy.getByTestId(liquidityVoteStatus).should(
|
||||||
'contain.text',
|
'contain.text',
|
||||||
'Currently expected to pass'
|
'Currently expected to pass'
|
||||||
@@ -321,18 +341,19 @@ context(
|
|||||||
'contain.text',
|
'contain.text',
|
||||||
'Currently expected to pass'
|
'Currently expected to pass'
|
||||||
);
|
);
|
||||||
cy.get_proposal_information_from_table('Expected to pass')
|
getProposalInformationFromTable('Expected to pass')
|
||||||
.contains('👍 by Token vote')
|
.contains('👍 by token vote')
|
||||||
.should('be.visible');
|
.should('be.visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
|
// 3001-VOTE-026 3001-VOTE-027 3001-VOTE-028 3001-VOTE-095 3001-VOTE-096 3005-PASN-001
|
||||||
it('Able to submit new asset proposal using min deadlines', function () {
|
it('Able to submit new asset proposal using min deadlines', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
|
const proposalTitle = 'Test new asset proposal';
|
||||||
cy.get(newProposalTitle).type('Test new asset proposal');
|
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||||
|
cy.get(newProposalTitle).type(proposalTitle);
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
|
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
|
||||||
let newAssetPayload = JSON.stringify(newAssetProposal);
|
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
@@ -348,7 +369,7 @@ context(
|
|||||||
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
|
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
|
||||||
'be.visible'
|
'be.visible'
|
||||||
);
|
);
|
||||||
cy.get(dialogCloseButton).click();
|
closeDialog();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
// cannot submit a proposal with ERC20 address already in use
|
// cannot submit a proposal with ERC20 address already in use
|
||||||
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
|
||||||
@@ -358,10 +379,21 @@ context(
|
|||||||
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
|
'PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
closeDialog();
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
cy.contains(proposalTitle)
|
||||||
|
.parentsUntil(proposalListItem)
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
|
});
|
||||||
|
cy.getByTestId(proposalTermsSection).within(() => {
|
||||||
|
cy.contains('USDT Coin').should('be.visible');
|
||||||
|
cy.contains('USDT').should('be.visible');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
it('Unable to submit new asset proposal with missing/invalid fields', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
|
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
cy.get(newProposalTitle).type('Invalid new asset proposal');
|
cy.get(newProposalTitle).type('Invalid new asset proposal');
|
||||||
@@ -377,13 +409,13 @@ context(
|
|||||||
const assetId =
|
const assetId =
|
||||||
'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d';
|
'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d';
|
||||||
|
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
enterUpdateAssetProposalDetails();
|
enterUpdateAssetProposalDetails();
|
||||||
cy.get(minVoteDeadline).click();
|
cy.get(minVoteDeadline).click();
|
||||||
cy.get(minEnactDeadline).click();
|
cy.get(minEnactDeadline).click();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
cy.get(proposalType)
|
cy.get(proposalType)
|
||||||
.contains('Update asset')
|
.contains('Update asset')
|
||||||
@@ -393,22 +425,28 @@ context(
|
|||||||
cy.getByTestId(viewProposalBtn).click();
|
cy.getByTestId(viewProposalBtn).click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('Proposed enactment') // 3001-VOTE-044
|
getProposalInformationFromTable('Proposed enactment') // 3001-VOTE-044
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.should('not.be.empty');
|
.should('not.be.empty');
|
||||||
|
// 3001-VOTE-030 3001-VOTE-031
|
||||||
|
cy.getByTestId(proposalTermsSection).within(() => {
|
||||||
|
cy.contains('UpdateAsset').should('be.visible');
|
||||||
|
cy.contains('UpdateERC20').should('be.visible');
|
||||||
|
cy.contains('"lifetimeLimit": "10"').should('be.visible');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to submit update asset proposal using max deadline', function () {
|
it.only('Able to submit update asset proposal using max deadline', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
enterUpdateAssetProposalDetails();
|
enterUpdateAssetProposalDetails();
|
||||||
cy.get(maxVoteDeadline).click();
|
cy.get(maxVoteDeadline).click();
|
||||||
cy.get(maxEnactDeadline).click();
|
cy.get(maxEnactDeadline).click();
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.wait_for_proposal_submitted();
|
waitForProposalSubmitted();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
|
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
cy.get(inputError).should('have.length', 3);
|
cy.get(inputError).should('have.length', 3);
|
||||||
});
|
});
|
||||||
@@ -428,7 +466,7 @@ context(
|
|||||||
cy.get(newProposalTitle).type('Test update asset proposal');
|
cy.get(newProposalTitle).type('Test update asset proposal');
|
||||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||||
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
|
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
|
||||||
let newAssetPayload = JSON.stringify(newAssetProposal);
|
const newAssetPayload = JSON.stringify(newAssetProposal);
|
||||||
cy.get(newProposalTerms).type(newAssetPayload, {
|
cy.get(newProposalTerms).type(newAssetPayload, {
|
||||||
parseSpecialCharSequences: false,
|
parseSpecialCharSequences: false,
|
||||||
delay: 2,
|
delay: 2,
|
||||||
+63
-62
@@ -1,9 +1,28 @@
|
|||||||
|
import type { testFreeformProposal } from '../../support/common-interfaces';
|
||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
import {
|
import {
|
||||||
createFreeformProposal,
|
createFreeformProposal,
|
||||||
createRawProposal,
|
createRawProposal,
|
||||||
|
createTenDigitUnixTimeStampForSpecifiedDays,
|
||||||
|
enterRawProposalBody,
|
||||||
generateFreeFormProposalTitle,
|
generateFreeFormProposalTitle,
|
||||||
|
getProposalIdFromList,
|
||||||
|
getProposalInformationFromTable,
|
||||||
|
getSortOrderOfSuppliedArray,
|
||||||
|
getSubmittedProposalFromProposalList,
|
||||||
|
goToMakeNewProposal,
|
||||||
governanceProposalType,
|
governanceProposalType,
|
||||||
|
voteForProposal,
|
||||||
|
waitForProposalSubmitted,
|
||||||
|
waitForProposalSync,
|
||||||
} from '../../support/governance.functions';
|
} from '../../support/governance.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-teardown.functions';
|
||||||
|
|
||||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||||
const openProposals = '[data-testid="open-proposals"]';
|
const openProposals = '[data-testid="open-proposals"]';
|
||||||
@@ -12,17 +31,17 @@ const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
|||||||
|
|
||||||
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
||||||
before('connect wallets and set approval limit', function () {
|
before('connect wallets and set approval limit', function () {
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit proposals tab', function () {
|
beforeEach('visit proposals tab', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(1);
|
ensureSpecifiedUnstakedTokensAreAssociated('1');
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
navigateTo(navigation.proposals);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
|
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
|
||||||
@@ -30,32 +49,30 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
const maxCloseDays = 3;
|
const maxCloseDays = 3;
|
||||||
|
|
||||||
// 3001-VOTE-005
|
// 3001-VOTE-005
|
||||||
let proposalDays = [
|
const proposalDays = [
|
||||||
minCloseDays + 1,
|
minCloseDays + 1,
|
||||||
maxCloseDays,
|
maxCloseDays,
|
||||||
minCloseDays + 3,
|
minCloseDays + 3,
|
||||||
minCloseDays + 2,
|
minCloseDays + 2,
|
||||||
];
|
];
|
||||||
for (var index = 0; index < proposalDays.length; index++) {
|
for (let index = 0; index < proposalDays.length; index++) {
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days(
|
enterRawProposalBody(
|
||||||
proposalDays[index]
|
createTenDigitUnixTimeStampForSpecifiedDays(proposalDays[index])
|
||||||
).then((closingDateTimestamp) => {
|
);
|
||||||
cy.enter_raw_proposal_body(closingDateTimestamp);
|
waitForProposalSubmitted();
|
||||||
});
|
waitForProposalSync();
|
||||||
cy.wait_for_proposal_submitted();
|
|
||||||
cy.wait_for_proposal_sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let arrayOfProposals = [];
|
const arrayOfProposals: string[] = [];
|
||||||
|
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.get(proposalDetailsTitle)
|
cy.get(proposalDetailsTitle)
|
||||||
.each((proposalTitleElement) => {
|
.each((proposalTitleElement) => {
|
||||||
arrayOfProposals.push(proposalTitleElement.text());
|
arrayOfProposals.push(proposalTitleElement.text());
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
cy.get_sort_order_of_supplied_array(arrayOfProposals).should(
|
cy.wrap(getSortOrderOfSuppliedArray(arrayOfProposals)).should(
|
||||||
'equal',
|
'equal',
|
||||||
'descending'
|
'descending'
|
||||||
);
|
);
|
||||||
@@ -67,7 +84,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
const proposalTitle = generateFreeFormProposalTitle();
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
|
|
||||||
createFreeformProposal(proposalTitle);
|
createFreeformProposal(proposalTitle);
|
||||||
cy.get_proposal_id_from_list(proposalTitle);
|
getProposalIdFromList(proposalTitle);
|
||||||
cy.get('@proposalIdText').then((proposalId) => {
|
cy.get('@proposalIdText').then((proposalId) => {
|
||||||
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
cy.get('[data-testid="set-proposals-filter-visible"]').click();
|
||||||
cy.get('[data-testid="filter-input"]').type(proposerId);
|
cy.get('[data-testid="filter-input"]').type(proposerId);
|
||||||
@@ -77,8 +94,8 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
|
|
||||||
it('Newly created proposals list - shows title and portion of summary', function () {
|
it('Newly created proposals list - shows title and portion of summary', function () {
|
||||||
createRawProposal(this.minProposerBalance); // 3001-VOTE-052
|
createRawProposal(this.minProposerBalance); // 3001-VOTE-052
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_proposal_id_from_list(rawProposal.rationale.title);
|
getProposalIdFromList(rawProposal.rationale.title);
|
||||||
cy.get('@proposalIdText').then((proposalId) => {
|
cy.get('@proposalIdText').then((proposalId) => {
|
||||||
cy.get(openProposals).within(() => {
|
cy.get(openProposals).within(() => {
|
||||||
// 3001-VOTE-008
|
// 3001-VOTE-008
|
||||||
@@ -102,21 +119,22 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
// 3001-VOTE-004
|
// 3001-VOTE-004
|
||||||
// 3001-VOTE-035
|
// 3001-VOTE-035
|
||||||
createRawProposal(this.minProposerBalance);
|
createRawProposal(this.minProposerBalance);
|
||||||
cy.get('@rawProposal').then((rawProposal) => {
|
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(
|
getSubmittedProposalFromProposalList(rawProposal.rationale.title).within(
|
||||||
rawProposal.rationale.title
|
() => {
|
||||||
).within(() => {
|
cy.get(viewProposalButton).should('be.visible').click();
|
||||||
cy.get(viewProposalButton).should('be.visible').click();
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
cy.get('@proposalIdText').then((proposalId) => {
|
cy.get('@proposalIdText').then((proposalId) => {
|
||||||
cy.get_proposal_information_from_table('ID')
|
getProposalInformationFromTable('ID')
|
||||||
.contains(proposalId)
|
.contains(String(proposalId))
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
cy.get_proposal_information_from_table('State')
|
getProposalInformationFromTable('State')
|
||||||
.contains('Open')
|
.contains('Open')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
cy.get_proposal_information_from_table('Type')
|
getProposalInformationFromTable('Type')
|
||||||
.contains('Freeform')
|
.contains('Freeform')
|
||||||
.and('be.visible');
|
.and('be.visible');
|
||||||
});
|
});
|
||||||
@@ -125,38 +143,21 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
|
|||||||
// 3001-VOTE-071
|
// 3001-VOTE-071
|
||||||
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||||
const proposalTitle = generateFreeFormProposalTitle();
|
const proposalTitle = generateFreeFormProposalTitle();
|
||||||
const requiredParticipation = 0.001;
|
|
||||||
|
|
||||||
createFreeformProposal(proposalTitle);
|
createFreeformProposal(proposalTitle);
|
||||||
|
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
|
||||||
cy.get_submitted_proposal_from_proposal_list(proposalTitle)
|
// 3001-VOTE-039
|
||||||
.as('submittedProposal')
|
cy.get(voteStatus).should('have.text', 'Participation not reached');
|
||||||
.within(() => {
|
cy.get(viewProposalButton).click();
|
||||||
// 3001-VOTE-039
|
});
|
||||||
cy.get(voteStatus).should('have.text', 'Participation not reached');
|
voteForProposal('for');
|
||||||
cy.get(viewProposalButton).click();
|
navigateTo(navigation.proposals);
|
||||||
});
|
getSubmittedProposalFromProposalList(proposalTitle).within(() => {
|
||||||
cy.vote_for_proposal('for');
|
cy.get(voteStatus).should('have.text', 'Set to pass');
|
||||||
cy.get_proposal_information_from_table('Total Supply')
|
cy.get(viewProposalButton).click();
|
||||||
.invoke('text')
|
});
|
||||||
.then((totalSupply) => {
|
getProposalInformationFromTable('Token participation met')
|
||||||
let tokensRequiredToAchieveResult = parseFloat(
|
.contains('👍')
|
||||||
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
|
.should('be.visible');
|
||||||
).toFixed(2);
|
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
|
||||||
tokensRequiredToAchieveResult
|
|
||||||
);
|
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
|
||||||
cy.get('@submittedProposal').within(() =>
|
|
||||||
cy.get(viewProposalButton).click()
|
|
||||||
);
|
|
||||||
cy.get_proposal_information_from_table('Token participation met')
|
|
||||||
.contains('👍')
|
|
||||||
.should('be.visible');
|
|
||||||
cy.navigate_to('proposals');
|
|
||||||
cy.get('@submittedProposal').within(() =>
|
|
||||||
cy.get(voteStatus).should('have.text', 'Set to pass')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+39
-37
@@ -1,3 +1,21 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
clickOnValidatorFromList,
|
||||||
|
closeStakingDialog,
|
||||||
|
stakingPageAssociateTokens,
|
||||||
|
stakingValidatorPageAddStake,
|
||||||
|
waitForBeginningOfEpoch,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import {
|
||||||
|
depositAsset,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
|
||||||
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
|
||||||
const vegaWalletUnstakedBalance =
|
const vegaWalletUnstakedBalance =
|
||||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||||
@@ -8,29 +26,29 @@ const rewardsTimeOut = { timeout: 60000 };
|
|||||||
context('rewards - flow', { tags: '@slow' }, function () {
|
context('rewards - flow', { tags: '@slow' }, function () {
|
||||||
before('set up environment to allow rewards', function () {
|
before('set up environment to allow rewards', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.deposit_asset(vegaAssetAddress, '1000');
|
depositAsset(vegaAssetAddress, '1000');
|
||||||
cy.validatorsSelfDelegate();
|
cy.validatorsSelfDelegate();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
topUpRewardsPool();
|
cy.VegaWalletTopUpRewardsPool(30, 200);
|
||||||
cy.navigate_to('validators');
|
navigateTo(navigation.validators);
|
||||||
cy.vega_wallet_teardown();
|
vegaWalletTeardown();
|
||||||
cy.staking_page_associate_tokens('6000');
|
stakingPageAssociateTokens('6000');
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
||||||
'contain',
|
'contain',
|
||||||
'6,000.0',
|
'6,000.0',
|
||||||
txTimeout
|
txTimeout
|
||||||
);
|
);
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
cy.click_on_validator_from_list(0);
|
clickOnValidatorFromList(0);
|
||||||
cy.staking_validator_page_add_stake('3000');
|
stakingValidatorPageAddStake('3000');
|
||||||
cy.close_staking_dialog();
|
closeStakingDialog();
|
||||||
cy.navigate_to('validators');
|
navigateTo(navigation.validators);
|
||||||
cy.click_on_validator_from_list(1);
|
clickOnValidatorFromList(1);
|
||||||
cy.staking_validator_page_add_stake('3000');
|
stakingValidatorPageAddStake('3000');
|
||||||
cy.close_staking_dialog();
|
closeStakingDialog();
|
||||||
cy.navigate_to('rewards');
|
navigateTo(navigation.rewards);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should display rewards per epoch', function () {
|
it('Should display rewards per epoch', function () {
|
||||||
@@ -54,7 +72,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get('h2').first().invoke('text').as('epochNumber');
|
cy.get('h2').first().invoke('text').as('epochNumber');
|
||||||
});
|
});
|
||||||
cy.wait_for_beginning_of_epoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.get('@epochNumber').then((epochNumber) => {
|
cy.get('@epochNumber').then((epochNumber) => {
|
||||||
cy.getByTestId(rewardsTable)
|
cy.getByTestId(rewardsTable)
|
||||||
.first()
|
.first()
|
||||||
@@ -76,28 +94,12 @@ context('rewards - flow', { tags: '@slow' }, function () {
|
|||||||
cy.get('h2').first().should('contain.text', 'EPOCH');
|
cy.get('h2').first().should('contain.text', 'EPOCH');
|
||||||
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
|
cy.getByTestId('individual-rewards-asset').should('have.text', 'Vega');
|
||||||
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD')
|
cy.getByTestId('ACCOUNT_TYPE_GLOBAL_REWARD')
|
||||||
.should('contain.text', '0.4415')
|
.should('contain.text', '0.1177')
|
||||||
.and('contain.text', '(44.15%)');
|
.and('contain.text', '(11.7733%)');
|
||||||
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
|
cy.getByTestId('ACCOUNT_TYPE_FEES_INFRASTRUCTURE')
|
||||||
.should('contain.text', '0.0004')
|
.should('contain.text', '0.0001')
|
||||||
.and('contain.text', '(44.15%)');
|
.and('contain.text', '(11.7733%)');
|
||||||
cy.getByTestId('total').should('have.text', '0.4419');
|
cy.getByTestId('total').should('have.text', '0.1179');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function topUpRewardsPool() {
|
|
||||||
// Must ensure that test wallet contains assets already and that the tests are within the start and end epochs
|
|
||||||
cy.exec(
|
|
||||||
`vega wallet transaction send --wallet ${Cypress.env(
|
|
||||||
'vegaWalletName'
|
|
||||||
)} --pubkey ${Cypress.env(
|
|
||||||
'vegaWalletPublicKey'
|
|
||||||
)} -p "./src/fixtures/wallet/passphrase" --network DV '{"transfer":{"fromAccountType":4,"toAccountType":12,"to":"0000000000000000000000000000000000000000000000000000000000000000","asset":"b4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b","amount":"1000000000000000000","recurring":{"startEpoch":30, "endEpoch": 200, "factor":"1"}}}' --home ${Cypress.env(
|
|
||||||
'vegaWalletLocation'
|
|
||||||
)}`,
|
|
||||||
{ failOnNonZeroExit: false }
|
|
||||||
)
|
|
||||||
.its('stderr')
|
|
||||||
.should('contain', '');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
@@ -1,876 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
|
|
||||||
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
|
|
||||||
const stakeValidatorListValidatorStake = '[col-id="stake"] > div > span';
|
|
||||||
const stakeRemoveStakeRadioButton = '[data-testid="remove-stake-radio"]';
|
|
||||||
const stakeTokenAmountInputBox = '[data-testid="token-amount-input"]';
|
|
||||||
const stakeTokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
|
||||||
const stakeNextEpochValue = '[data-testid="stake-next-epoch"]';
|
|
||||||
const stakeThisEpochValue = '[data-testid="stake-this-epoch"]';
|
|
||||||
const stakeAddStakeRadioButton = '[data-testid="add-stake-radio"]';
|
|
||||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
|
||||||
const totalStake = '[data-testid="total-stake"]';
|
|
||||||
const stakeShare = '[data-testid="stake-percentage"]';
|
|
||||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
|
||||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
|
||||||
const vegaWalletUnstakedBalance =
|
|
||||||
'[data-testid="vega-wallet-balance-unstaked"]:visible';
|
|
||||||
const vegaWalletStakedBalances =
|
|
||||||
'[data-testid="vega-wallet-balance-staked-validators"]';
|
|
||||||
const ethWalletAssociatedBalances =
|
|
||||||
'[data-testid="eth-wallet-associated-balances"]';
|
|
||||||
const ethWalletTotalAssociatedBalance =
|
|
||||||
'[data-testid="currency-locked"]:visible';
|
|
||||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]:visible';
|
|
||||||
const vegaWallet = '[data-testid="vega-wallet"]';
|
|
||||||
const partValidatorId = '…';
|
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
|
||||||
const epochTimeout = Cypress.env('epochTimeout');
|
|
||||||
|
|
||||||
context(
|
|
||||||
'Staking Tab - with eth and vega wallets connected',
|
|
||||||
{ tags: '@slow' },
|
|
||||||
function () {
|
|
||||||
// 2001-STKE-002, 2001-STKE-032
|
|
||||||
before('visit staking tab and connect vega wallet', function () {
|
|
||||||
cy.visit('/');
|
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Eth wallet - contains VEGA tokens', function () {
|
|
||||||
beforeEach(
|
|
||||||
'teardown wallet & drill into a specific validator',
|
|
||||||
function () {
|
|
||||||
cy.reload();
|
|
||||||
cy.wait_for_spinner();
|
|
||||||
cy.connectVegaWallet();
|
|
||||||
cy.ethereum_wallet_connect();
|
|
||||||
cy.vega_wallet_teardown();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('Able to stake against a validator - using vega from wallet', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('3.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
|
||||||
.contains(vegaWalletPublicKeyShort, txTimeout)
|
|
||||||
.parent()
|
|
||||||
.should('contain', 3.0, txTimeout);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
// 2001-STKE-031
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
// 2001-STKE-039
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', 2.0, txTimeout)
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout) // 2001-STKE-016 2001-STKE-038
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(stakeThisEpochValue, epochTimeout) // 2001-STKE-013
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
// 2002-SINC-007
|
|
||||||
cy.validate_validator_list_total_stake_and_share(
|
|
||||||
'0',
|
|
||||||
'2.00',
|
|
||||||
'100.00%'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to stake against a validator - using vega from vesting contract', function () {
|
|
||||||
cy.staking_page_associate_tokens('3', { type: 'contract' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('3.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
|
||||||
.contains(vegaWalletPublicKeyShort, txTimeout)
|
|
||||||
.parent()
|
|
||||||
.should('contain', 3.0, txTimeout);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', 2.0, txTimeout)
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(stakeThisEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share(
|
|
||||||
'0',
|
|
||||||
'2.00',
|
|
||||||
'100.00%'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
|
|
||||||
cy.staking_page_associate_tokens('3', { type: 'contract' });
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
cy.staking_page_associate_tokens('4', { type: 'wallet' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
7.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('3.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('4.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
4.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('6');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', 6.0, txTimeout)
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(6.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(stakeThisEpochValue, epochTimeout)
|
|
||||||
.contains(6.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share(
|
|
||||||
'0',
|
|
||||||
'6.00',
|
|
||||||
'100.00%'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to stake against multiple validators', function () {
|
|
||||||
cy.staking_page_associate_tokens('5');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
5.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.parent()
|
|
||||||
.should('contain', 2.0, txTimeout);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(1);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('1');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('have.length', 2, txTimeout)
|
|
||||||
.eq(0)
|
|
||||||
.should('contain', 2.0, txTimeout);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.eq(1)
|
|
||||||
.should('contain', 1.0, txTimeout);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.get(`[row-id="${0}"]`).within(() => {
|
|
||||||
cy.get(stakeValidatorListTotalStake)
|
|
||||||
.should('have.text', '2.00')
|
|
||||||
.and('be.visible');
|
|
||||||
cy.get(stakeValidatorListTotalShare)
|
|
||||||
.should('have.text', '66.67%')
|
|
||||||
.and('be.visible');
|
|
||||||
cy.get(stakeValidatorListValidatorStake)
|
|
||||||
.scrollIntoView()
|
|
||||||
.should('have.text', '2.00')
|
|
||||||
.and('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(`[row-id="${1}"]`).within(() => {
|
|
||||||
cy.get(stakeValidatorListTotalStake)
|
|
||||||
.scrollIntoView()
|
|
||||||
.should('have.text', '1.00')
|
|
||||||
.and('be.visible');
|
|
||||||
cy.get(stakeValidatorListTotalShare)
|
|
||||||
.should('have.text', '33.33%')
|
|
||||||
.and('be.visible');
|
|
||||||
cy.get(stakeValidatorListValidatorStake)
|
|
||||||
.scrollIntoView()
|
|
||||||
.should('have.text', '1.00')
|
|
||||||
.and('be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2001-STKE-041
|
|
||||||
it(
|
|
||||||
'Able to remove part of a stake against a validator',
|
|
||||||
{ tags: '@smoke' },
|
|
||||||
function () {
|
|
||||||
cy.staking_page_associate_tokens('4');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
4.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('3');
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(3.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
// 2001-STKE-040
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
// 2001-STKE-044, 2001-STKE-048
|
|
||||||
cy.staking_validator_page_remove_stake('1');
|
|
||||||
|
|
||||||
// 2001-STKE-049
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout).contains(2.0, epochTimeout);
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(stakeThisEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(totalStake, epochTimeout).should('contain.text', '2');
|
|
||||||
cy.get(stakeShare, epochTimeout).should('have.text', '100%');
|
|
||||||
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share(
|
|
||||||
'0',
|
|
||||||
'2.00',
|
|
||||||
'100.00%'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2001-STKE-045
|
|
||||||
it('Able to remove a full stake against a validator', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('1');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list('0');
|
|
||||||
|
|
||||||
cy.staking_validator_page_remove_stake('1');
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(0.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(0.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(stakeThisEpochValue, epochTimeout)
|
|
||||||
.contains(0.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'not.exist',
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Unable to remove a stake with a negative value for a validator', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.get(stakeRemoveStakeRadioButton, txTimeout).click();
|
|
||||||
|
|
||||||
cy.get(stakeTokenAmountInputBox).type('-0.1');
|
|
||||||
|
|
||||||
cy.contains('Waiting for next epoch to start', epochTimeout);
|
|
||||||
|
|
||||||
cy.get(stakeTokenSubmitButton)
|
|
||||||
.should('be.disabled', epochTimeout)
|
|
||||||
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
|
|
||||||
.and('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(stakeNextEpochValue, epochTimeout)
|
|
||||||
.contains(2.0, epochTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.get(stakeRemoveStakeRadioButton).click();
|
|
||||||
|
|
||||||
cy.get(stakeTokenAmountInputBox).type(4);
|
|
||||||
|
|
||||||
cy.contains('Waiting for next epoch to start', epochTimeout);
|
|
||||||
|
|
||||||
cy.get(stakeTokenSubmitButton)
|
|
||||||
.should('be.disabled', epochTimeout)
|
|
||||||
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
|
|
||||||
.and('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Disassociating all wallet tokens max - removes all staked tokens', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list('1');
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_disassociate_all_tokens('wallet');
|
|
||||||
|
|
||||||
cy.get(ethWalletContainer).within(() => {
|
|
||||||
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('0.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
'0.00'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'not.exist',
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Disassociating all vesting contract tokens max - removes all staked tokens', function () {
|
|
||||||
cy.staking_page_associate_tokens('3', { type: 'contract' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list('1');
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_disassociate_all_tokens('contract');
|
|
||||||
|
|
||||||
cy.get(ethWalletContainer).within(() => {
|
|
||||||
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('0.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
'0.00'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'not.exist',
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share('0', '0.00', '0.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
2.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_disassociate_tokens('1');
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('2.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
'2.00'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', 2.0, txTimeout)
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.navigate_to('validators');
|
|
||||||
|
|
||||||
cy.validate_validator_list_total_stake_and_share(
|
|
||||||
'0',
|
|
||||||
'2.00',
|
|
||||||
'100.00%'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
|
||||||
// 2001-STKE-004
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_associate_tokens('4');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
7.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
|
||||||
// 2001-STKE-004
|
|
||||||
cy.staking_page_associate_tokens('3', { type: 'contract' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_associate_tokens('4', { type: 'contract' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
7.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
|
|
||||||
// 2001-STKE-004
|
|
||||||
cy.staking_page_associate_tokens('3', { type: 'wallet' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_associate_tokens('4', { type: 'contract' });
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
7.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
|
|
||||||
// 2001-STKE-004
|
|
||||||
cy.staking_page_associate_tokens('6');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
6.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(1);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('4');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
cy.staking_page_associate_tokens('6');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
'12.00'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', '4.0', txTimeout)
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.get(vegaWalletStakedBalances, txTimeout)
|
|
||||||
.should('contain', '8.0')
|
|
||||||
.and('contain', partValidatorId);
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
0.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () {
|
|
||||||
cy.staking_page_associate_tokens('3');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
3.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.staking_validator_page_add_stake('2');
|
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
|
|
||||||
'contain',
|
|
||||||
1.0,
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.close_staking_dialog();
|
|
||||||
|
|
||||||
cy.click_on_validator_from_list(0);
|
|
||||||
|
|
||||||
cy.get(stakeAddStakeRadioButton).click();
|
|
||||||
|
|
||||||
cy.get(stakeMaximumTokens, { timeout: 60000 }).click();
|
|
||||||
|
|
||||||
cy.get(stakeTokenSubmitButton).should('contain', 'Add 1 $VEGA tokens');
|
|
||||||
});
|
|
||||||
|
|
||||||
after('teardown wallet', function () {
|
|
||||||
cy.vega_wallet_teardown();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@@ -0,0 +1,501 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
import {
|
||||||
|
verifyUnstakedBalance,
|
||||||
|
verifyStakedBalance,
|
||||||
|
verifyEthWalletTotalAssociatedBalance,
|
||||||
|
verifyEthWalletAssociatedBalance,
|
||||||
|
waitForSpinner,
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
clickOnValidatorFromList,
|
||||||
|
closeStakingDialog,
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated,
|
||||||
|
stakingPageAssociateTokens,
|
||||||
|
stakingPageDisassociateAllTokens,
|
||||||
|
stakingPageDisassociateTokens,
|
||||||
|
stakingValidatorPageAddStake,
|
||||||
|
stakingValidatorPageRemoveStake,
|
||||||
|
validateValidatorListTotalStakeAndShare,
|
||||||
|
waitForBeginningOfEpoch,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import {
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
const stakeValidatorListTotalStake = 'total-stake';
|
||||||
|
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||||
|
const stakeValidatorListStakePercentage = 'stake-percentage';
|
||||||
|
const userStakeBtn = 'my-stake-btn';
|
||||||
|
const userStake = 'user-stake';
|
||||||
|
const userStakeShare = 'user-stake-share';
|
||||||
|
const viewAllValidatorsToggle = 'validators-view-toggle-all';
|
||||||
|
const viewStakedByMeToggle = 'validators-view-toggle-myStake';
|
||||||
|
const stakeRemoveStakeRadioButton = 'remove-stake-radio';
|
||||||
|
const stakeTokenAmountInputBox = 'token-amount-input';
|
||||||
|
const stakeTokenSubmitButton = 'token-input-submit-button';
|
||||||
|
const stakeAddStakeRadioButton = 'add-stake-radio';
|
||||||
|
const stakeMaximumTokens = 'token-amount-use-maximum';
|
||||||
|
const vegaWalletAssociatedBalance = 'currency-value';
|
||||||
|
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
|
||||||
|
const ethWalletContainer = 'ethereum-wallet';
|
||||||
|
const vegaWallet = 'vega-wallet';
|
||||||
|
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||||
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
|
const epochTimeout = Cypress.env('epochTimeout');
|
||||||
|
|
||||||
|
context(
|
||||||
|
'Staking Tab - with eth and vega wallets connected',
|
||||||
|
{ tags: '@slow' },
|
||||||
|
function () {
|
||||||
|
// 2001-STKE-002, 2001-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');
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Eth wallet - contains VEGA tokens', function () {
|
||||||
|
beforeEach(
|
||||||
|
'teardown wallet & drill into a specific validator',
|
||||||
|
function () {
|
||||||
|
cy.reload();
|
||||||
|
waitForSpinner();
|
||||||
|
cy.connectVegaWallet();
|
||||||
|
ethereumWalletConnect();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
// 2001-STKE-033, 2001-STKE-034, 2001-STKE-037
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
// 2001-STKE-039
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
verifyNextEpochValue(2.0); // 2001-STKE-016 2001-STKE-038
|
||||||
|
verifyThisEpochValue(2.0); // 2001-STKE-013
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
|
||||||
|
// 2002-SINC-007
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to view validators staked by me', function () {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated('4');
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
cy.getByTestId(userStake, epochTimeout)
|
||||||
|
.first()
|
||||||
|
.should('have.text', '2.00');
|
||||||
|
cy.getByTestId('total-stake').first().realHover();
|
||||||
|
cy.getByTestId('staked-by-user-tooltip')
|
||||||
|
.first()
|
||||||
|
.should('have.text', 'Staked by me: 2.00');
|
||||||
|
cy.getByTestId('total-pending-stake').first().realHover();
|
||||||
|
cy.getByTestId('pending-user-stake-tooltip')
|
||||||
|
.first()
|
||||||
|
.should('have.text', 'My pending stake: 0.00');
|
||||||
|
cy.getByTestId(userStakeShare).invoke('text').should('not.be.empty'); // Adjust when #3286 is resolved
|
||||||
|
cy.getByTestId(userStakeBtn).should('exist').click();
|
||||||
|
verifyThisEpochValue(2.0);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
cy.getByTestId(viewStakedByMeToggle).click();
|
||||||
|
cy.getByTestId(userStakeBtn).should('have.length', 1);
|
||||||
|
cy.getByTestId(viewAllValidatorsToggle).click();
|
||||||
|
clickOnValidatorFromList(1);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
cy.getByTestId(viewStakedByMeToggle).click();
|
||||||
|
cy.getByTestId(userStakeBtn).should('have.length', 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to stake against a validator - using vega from vesting contract', function () {
|
||||||
|
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||||
|
verifyEthWalletAssociatedBalance('3.0');
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
verifyNextEpochValue(2.0);
|
||||||
|
verifyThisEpochValue(2.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to stake against a validator - using vega from both wallet and vesting contract', function () {
|
||||||
|
vegaWalletTeardown();
|
||||||
|
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
stakingPageAssociateTokens('4', { type: 'wallet' });
|
||||||
|
verifyUnstakedBalance(7.0);
|
||||||
|
verifyEthWalletTotalAssociatedBalance('3.0');
|
||||||
|
verifyEthWalletTotalAssociatedBalance('4.0');
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('6');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
verifyStakedBalance(6.0);
|
||||||
|
verifyNextEpochValue(6.0);
|
||||||
|
verifyThisEpochValue(6.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '6.00', '100.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to stake against multiple validators', function () {
|
||||||
|
stakingPageAssociateTokens('5');
|
||||||
|
verifyUnstakedBalance(5.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||||
|
.parent()
|
||||||
|
.should('contain', 2.0, txTimeout);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
clickOnValidatorFromList(1);
|
||||||
|
stakingValidatorPageAddStake('1');
|
||||||
|
verifyUnstakedBalance(2.0);
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||||
|
.should('have.length', 4, txTimeout)
|
||||||
|
.eq(0)
|
||||||
|
.should('contain', 2.0, txTimeout);
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout)
|
||||||
|
.eq(1)
|
||||||
|
.should('contain', 1.0, txTimeout);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
cy.get(`[row-id="${0}"]`).within(() => {
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
|
.should('have.text', '2.00')
|
||||||
|
.and('be.visible');
|
||||||
|
cy.getByTestId(stakeValidatorListTotalShare)
|
||||||
|
.should('have.text', '66.67%')
|
||||||
|
.and('be.visible');
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
|
.scrollIntoView()
|
||||||
|
.should('have.text', '2.00')
|
||||||
|
.and('be.visible');
|
||||||
|
});
|
||||||
|
cy.get(`[row-id="${1}"]`).within(() => {
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
|
.scrollIntoView()
|
||||||
|
.should('have.text', '1.00')
|
||||||
|
.and('be.visible');
|
||||||
|
cy.getByTestId(stakeValidatorListTotalShare)
|
||||||
|
.should('have.text', '33.33%')
|
||||||
|
.and('be.visible');
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake)
|
||||||
|
.scrollIntoView()
|
||||||
|
.should('have.text', '1.00')
|
||||||
|
.and('be.visible');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2001-STKE-041
|
||||||
|
it(
|
||||||
|
'Able to remove part of a stake against a validator',
|
||||||
|
{ tags: '@smoke' },
|
||||||
|
function () {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated('4');
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('3');
|
||||||
|
verifyNextEpochValue(3.0);
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
// 2001-STKE-040
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
// 2001-STKE-044, 2001-STKE-048
|
||||||
|
stakingValidatorPageRemoveStake('1');
|
||||||
|
// 2001-STKE-049
|
||||||
|
verifyNextEpochValue(2.0);
|
||||||
|
verifyUnstakedBalance(2.0);
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
verifyNextEpochValue(2.0);
|
||||||
|
verifyThisEpochValue(2.0);
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||||
|
'contain.text',
|
||||||
|
'2'
|
||||||
|
);
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.getByTestId(stakeValidatorListStakePercentage).should(
|
||||||
|
'have.text',
|
||||||
|
'100%'
|
||||||
|
);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2001-STKE-045
|
||||||
|
it('Able to remove a full stake against a validator', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('1');
|
||||||
|
verifyUnstakedBalance(2.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageRemoveStake('1');
|
||||||
|
verifyNextEpochValue(0.0);
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
verifyNextEpochValue(0.0);
|
||||||
|
verifyThisEpochValue(0.0);
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||||
|
'not.exist',
|
||||||
|
txTimeout
|
||||||
|
);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||||
|
|
||||||
|
cy.getByTestId(userStakeBtn).should('not.exist');
|
||||||
|
cy.getByTestId(userStake).should('not.exist');
|
||||||
|
cy.getByTestId(userStakeShare).should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Unable to remove a stake with a negative value for a validator', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyNextEpochValue(2.0);
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click();
|
||||||
|
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
|
||||||
|
cy.contains('Waiting for next epoch to start', epochTimeout);
|
||||||
|
cy.getByTestId(stakeTokenSubmitButton)
|
||||||
|
.should('be.disabled', epochTimeout)
|
||||||
|
.and('contain', `Remove -0.1 $VEGA tokens at the end of epoch`)
|
||||||
|
.and('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Unable to remove a stake greater than staked amount next epoch for a validator', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyNextEpochValue(2.0);
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
cy.getByTestId(stakeRemoveStakeRadioButton).click();
|
||||||
|
cy.getByTestId(stakeTokenAmountInputBox).type('4');
|
||||||
|
cy.contains('Waiting for next epoch to start', epochTimeout);
|
||||||
|
cy.getByTestId(stakeTokenSubmitButton)
|
||||||
|
.should('be.disabled', epochTimeout)
|
||||||
|
.and('contain', `Remove 4 $VEGA tokens at the end of epoch`)
|
||||||
|
.and('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Disassociating all wallet tokens max - removes all staked tokens', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(1);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageDisassociateAllTokens();
|
||||||
|
cy.getByTestId(ethWalletContainer).within(() => {
|
||||||
|
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
||||||
|
});
|
||||||
|
verifyEthWalletTotalAssociatedBalance('0.0');
|
||||||
|
cy.getByTestId(vegaWallet).within(() => {
|
||||||
|
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
|
'contain',
|
||||||
|
'0.00'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||||
|
'not.exist',
|
||||||
|
txTimeout
|
||||||
|
);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Disassociating all vesting contract tokens max - removes all staked tokens', function () {
|
||||||
|
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(1);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageDisassociateAllTokens('contract');
|
||||||
|
cy.getByTestId(ethWalletContainer).within(() => {
|
||||||
|
cy.contains(vegaWalletPublicKeyShort, txTimeout).should('not.exist');
|
||||||
|
});
|
||||||
|
verifyEthWalletTotalAssociatedBalance('0.0');
|
||||||
|
cy.getByTestId(vegaWallet).within(() => {
|
||||||
|
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
|
'contain',
|
||||||
|
'0.00'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
|
||||||
|
'not.exist',
|
||||||
|
txTimeout
|
||||||
|
);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '0.00', '0.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Disassociating some tokens - prioritizes unstaked tokens', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageDisassociateTokens('1');
|
||||||
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
|
cy.getByTestId(vegaWallet).within(() => {
|
||||||
|
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
|
'contain',
|
||||||
|
'2.00'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
verifyStakedBalance(2.0);
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
validateValidatorListTotalStakeAndShare('0', '2.00', '100.00%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||||
|
// 2001-STKE-004
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('3');
|
||||||
|
verifyStakedBalance(3.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageAssociateTokens('4');
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
verifyStakedBalance(7.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
|
||||||
|
// 2001-STKE-004
|
||||||
|
stakingPageAssociateTokens('3', { type: 'contract' });
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('3');
|
||||||
|
verifyStakedBalance(3.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageAssociateTokens('4', { type: 'contract' });
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
verifyStakedBalance(7.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
|
||||||
|
// 2001-STKE-004
|
||||||
|
stakingPageAssociateTokens('3', { type: 'wallet' });
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('3');
|
||||||
|
verifyStakedBalance(3.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageAssociateTokens('4', { type: 'contract' });
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
verifyStakedBalance(7.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
|
||||||
|
// 2001-STKE-004
|
||||||
|
stakingPageAssociateTokens('6');
|
||||||
|
verifyUnstakedBalance(6.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
clickOnValidatorFromList(1);
|
||||||
|
stakingValidatorPageAddStake('4');
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
stakingPageAssociateTokens('6');
|
||||||
|
cy.getByTestId(vegaWallet).within(() => {
|
||||||
|
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
|
'contain',
|
||||||
|
'12.00'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
verifyStakedBalance(4.0);
|
||||||
|
verifyStakedBalance(8.0);
|
||||||
|
verifyUnstakedBalance(0.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Selecting use maximum where tokens are already staked - suggests the unstaked token amount', function () {
|
||||||
|
stakingPageAssociateTokens('3');
|
||||||
|
verifyUnstakedBalance(3.0);
|
||||||
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
stakingValidatorPageAddStake('2');
|
||||||
|
verifyUnstakedBalance(1.0);
|
||||||
|
closeStakingDialog();
|
||||||
|
clickOnValidatorFromList(0);
|
||||||
|
cy.getByTestId(stakeAddStakeRadioButton).click();
|
||||||
|
cy.getByTestId(stakeMaximumTokens, { timeout: 60000 }).click();
|
||||||
|
cy.getByTestId(stakeTokenSubmitButton).should(
|
||||||
|
'contain',
|
||||||
|
'Add 1 $VEGA tokens'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach('Teardown Wallet', function () {
|
||||||
|
vegaWalletTeardown();
|
||||||
|
});
|
||||||
|
|
||||||
|
function verifyNextEpochValue(amount: number) {
|
||||||
|
cy.getByTestId('stake-next-epoch', epochTimeout)
|
||||||
|
.contains(amount, epochTimeout)
|
||||||
|
.should('be.visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyThisEpochValue(amount: number) {
|
||||||
|
cy.getByTestId('stake-this-epoch', epochTimeout) // 2001-STKE-013
|
||||||
|
.contains(amount, epochTimeout)
|
||||||
|
.should('be.visible');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
+85
-139
@@ -1,13 +1,31 @@
|
|||||||
|
import {
|
||||||
|
verifyEthWalletTotalAssociatedBalance,
|
||||||
|
verifyEthWalletAssociatedBalance,
|
||||||
|
waitForSpinner,
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
stakingPageAssociateTokens,
|
||||||
|
stakingPageDisassociateAllTokens,
|
||||||
|
stakingPageDisassociateTokens,
|
||||||
|
validateWalletCurrency,
|
||||||
|
} from '../../support/staking.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import {
|
||||||
|
vegaWalletAssociate,
|
||||||
|
vegaWalletDisassociate,
|
||||||
|
vegaWalletSetSpecifiedApprovalAmount,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
|
||||||
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
|
||||||
const ethWalletAssociatedBalances =
|
|
||||||
'[data-testid="eth-wallet-associated-balances"]';
|
|
||||||
const ethWalletTotalAssociatedBalance = '[data-testid="currency-locked"]';
|
|
||||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||||
const vegaWalletUnstakedBalance =
|
const vegaWalletUnstakedBalance =
|
||||||
'[data-testid="vega-wallet-balance-unstaked"]';
|
'[data-testid="vega-wallet-balance-unstaked"]';
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
|
||||||
const ethWalletAssociateButton = '[href="/token/associate"]';
|
const ethWalletAssociateButton = '[data-testid="associate-btn"]';
|
||||||
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
||||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||||
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||||
@@ -28,7 +46,7 @@ context(
|
|||||||
before('visit staking tab and connect vega wallet', function () {
|
before('visit staking tab and connect vega wallet', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
// 0005-ETXN-001
|
// 0005-ETXN-001
|
||||||
cy.vega_wallet_set_specified_approval_amount('1000');
|
vegaWalletSetSpecifiedApprovalAmount('1000');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Eth wallet - contains VEGA tokens', function () {
|
describe('Eth wallet - contains VEGA tokens', function () {
|
||||||
@@ -36,11 +54,10 @@ context(
|
|||||||
'teardown wallet & drill into a specific validator',
|
'teardown wallet & drill into a specific validator',
|
||||||
function () {
|
function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.ethereum_wallet_connect();
|
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.vega_wallet_teardown();
|
ethereumWalletConnect();
|
||||||
cy.navigate_to('validators');
|
vegaWalletTeardown();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -57,26 +74,21 @@ context(
|
|||||||
//0005-ETXN-006
|
//0005-ETXN-006
|
||||||
//0005-ETXN-003
|
//0005-ETXN-003
|
||||||
//0005-ETXN-005
|
//0005-ETXN-005
|
||||||
cy.staking_page_associate_tokens('2', { skipConfirmation: true });
|
stakingPageAssociateTokens('2', { skipConfirmation: true });
|
||||||
|
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
cy.validate_wallet_currency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
|
|
||||||
// 0005-ETXN-002
|
// 0005-ETXN-002
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 2.0);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
.contains('2.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
@@ -92,50 +104,30 @@ context(
|
|||||||
// 1004-ASSO-029
|
// 1004-ASSO-029
|
||||||
// 1004-ASSO-031
|
// 1004-ASSO-031
|
||||||
|
|
||||||
cy.staking_page_associate_tokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 2.0);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('2.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
stakingPageDisassociateTokens('2');
|
||||||
cy.staking_page_disassociate_tokens('2');
|
|
||||||
|
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
cy.validate_wallet_currency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '0.00');
|
validateWalletCurrency('Total associated after pending', '0.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
|
cy.getByTestId('eth-wallet-associated-balances', txTimeout).should(
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout).should('not.exist');
|
'not.exist'
|
||||||
|
);
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('0.00');
|
||||||
.contains('0.00', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () {
|
it('Able to associate more tokens than the approved amount of 1000 - requires re-approval', function () {
|
||||||
//1004-ASSO-011
|
//1004-ASSO-011
|
||||||
cy.staking_page_associate_tokens('1001', { approve: true });
|
stakingPageAssociateTokens('1001', { approve: true });
|
||||||
|
verifyEthWalletAssociatedBalance('1,001.00');
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('1,001.00');
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent()
|
|
||||||
.should('contain', '1,001.00', txTimeout);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('1,001.00', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
|
||||||
'contain',
|
'contain',
|
||||||
@@ -145,26 +137,14 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
it('Able to disassociate a partial amount of tokens currently associated', function () {
|
||||||
cy.staking_page_associate_tokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
stakingPageDisassociateTokens('1');
|
||||||
cy.staking_page_disassociate_tokens('1');
|
verifyEthWalletAssociatedBalance('1.0');
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 1.0);
|
|
||||||
|
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 1.0);
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
|
||||||
});
|
});
|
||||||
@@ -174,32 +154,24 @@ context(
|
|||||||
// 1004-ASSO-026
|
// 1004-ASSO-026
|
||||||
const warningText =
|
const warningText =
|
||||||
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
|
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
|
||||||
|
stakingPageAssociateTokens('2');
|
||||||
cy.staking_page_associate_tokens('2');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
|
|
||||||
cy.get(ethWalletDissociateButton).click();
|
cy.get(ethWalletDissociateButton).click();
|
||||||
cy.get(disassociationWarning).should('contain', warningText);
|
cy.get(disassociationWarning).should('contain', warningText);
|
||||||
|
stakingPageDisassociateAllTokens();
|
||||||
cy.staking_page_disassociate_all_tokens();
|
|
||||||
|
|
||||||
cy.get(ethWalletContainer).within(() => {
|
cy.get(ethWalletContainer).within(() => {
|
||||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||||
'not.exist'
|
'not.exist'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(ethWalletContainer).within(() => {
|
cy.get(ethWalletContainer).within(() => {
|
||||||
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
|
||||||
'not.exist'
|
'not.exist'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
|
||||||
});
|
});
|
||||||
@@ -211,8 +183,9 @@ context(
|
|||||||
// 1004-ASSO-018
|
// 1004-ASSO-018
|
||||||
// 1004-ASSO-024
|
// 1004-ASSO-024
|
||||||
// 1004-ASSO-023
|
// 1004-ASSO-023
|
||||||
|
// 1004-ASSO-032
|
||||||
|
|
||||||
cy.staking_page_associate_tokens('2', {
|
stakingPageAssociateTokens('2', {
|
||||||
type: 'contract',
|
type: 'contract',
|
||||||
skipConfirmation: true,
|
skipConfirmation: true,
|
||||||
});
|
});
|
||||||
@@ -221,47 +194,30 @@ context(
|
|||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
cy.validate_wallet_currency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
|
verifyEthWalletAssociatedBalance('2.0');
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('2.0');
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 2.0);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('2.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||||
cy.staking_page_disassociate_tokens('1', {
|
stakingPageDisassociateTokens('1', {
|
||||||
type: 'contract',
|
type: 'contract',
|
||||||
skipConfirmation: true,
|
skipConfirmation: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
cy.validate_wallet_currency('Pending association', '1.00');
|
validateWalletCurrency('Pending association', '1.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '1.00');
|
validateWalletCurrency('Total associated after pending', '1.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
|
verifyEthWalletAssociatedBalance('1.0');
|
||||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
verifyEthWalletTotalAssociatedBalance('1.0');
|
||||||
.contains(vegaWalletPublicKeyShort)
|
|
||||||
.parent(txTimeout)
|
|
||||||
.should('contain', 1.0);
|
|
||||||
|
|
||||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
|
||||||
.contains('1.0', txTimeout)
|
|
||||||
.should('be.visible');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to associate & disassociate both wallet and vesting contract tokens', function () {
|
it('Able to associate & disassociate both wallet and vesting contract tokens', function () {
|
||||||
@@ -269,11 +225,9 @@ context(
|
|||||||
// 1004-ASSO-020
|
// 1004-ASSO-020
|
||||||
// 1004-ASSO-021
|
// 1004-ASSO-021
|
||||||
// 1004-ASSO-022
|
// 1004-ASSO-022
|
||||||
|
stakingPageAssociateTokens('21', { type: 'wallet' });
|
||||||
cy.staking_page_associate_tokens('21', { type: 'wallet' });
|
|
||||||
cy.get('button').contains('Select a validator to nominate').click();
|
cy.get('button').contains('Select a validator to nominate').click();
|
||||||
cy.staking_page_associate_tokens('37', { type: 'contract' });
|
stakingPageAssociateTokens('37', { type: 'contract' });
|
||||||
|
|
||||||
cy.get(vestingContractSection).within(() => {
|
cy.get(vestingContractSection).within(() => {
|
||||||
cy.get(associatedKey).should(
|
cy.get(associatedKey).should(
|
||||||
'contain',
|
'contain',
|
||||||
@@ -281,7 +235,6 @@ context(
|
|||||||
);
|
);
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 37);
|
cy.get(associatedAmount, txTimeout).should('contain', 37);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaInWalletSection).within(() => {
|
cy.get(vegaInWalletSection).within(() => {
|
||||||
cy.get(associatedKey).should(
|
cy.get(associatedKey).should(
|
||||||
'contain',
|
'contain',
|
||||||
@@ -289,27 +242,21 @@ context(
|
|||||||
);
|
);
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
cy.get(associatedAmount, txTimeout).should('contain', 21);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
|
||||||
});
|
});
|
||||||
|
stakingPageDisassociateTokens('6', { type: 'contract' });
|
||||||
cy.staking_page_disassociate_tokens('6', { type: 'contract' });
|
|
||||||
cy.get(vestingContractSection).within(() => {
|
cy.get(vestingContractSection).within(() => {
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
cy.get(associatedAmount, txTimeout).should('contain', 31);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
|
||||||
});
|
});
|
||||||
|
navigateTo(navigation.validators);
|
||||||
cy.navigate_to('validators');
|
stakingPageDisassociateTokens('9', { type: 'wallet' });
|
||||||
|
|
||||||
cy.staking_page_disassociate_tokens('9', { type: 'wallet' });
|
|
||||||
cy.get(vegaInWalletSection).within(() => {
|
cy.get(vegaInWalletSection).within(() => {
|
||||||
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
cy.get(associatedAmount, txTimeout).should('contain', 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
|
||||||
});
|
});
|
||||||
@@ -319,42 +266,41 @@ context(
|
|||||||
// 1004-ASSO-008
|
// 1004-ASSO-008
|
||||||
// 1004-ASSO-010
|
// 1004-ASSO-010
|
||||||
// No warning visible as described in AC, but the button is disabled
|
// No warning visible as described in AC, but the button is disabled
|
||||||
|
|
||||||
cy.get(ethWalletAssociateButton).first().click();
|
cy.get(ethWalletAssociateButton).first().click();
|
||||||
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
|
||||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
|
||||||
cy.get(tokenAmountInputBox, { timeout: 10000 }).type(6500000);
|
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
|
||||||
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
|
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1004-ASSO-004
|
// 1004-ASSO-004
|
||||||
|
|
||||||
it('Pending association outside of app is shown', function () {
|
it('Pending association outside of app is shown', function () {
|
||||||
cy.vega_wallet_associate('2');
|
vegaWalletAssociate('2');
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
cy.validate_wallet_currency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
validateWalletCurrency('Total associated after pending', '2.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
cy.validate_wallet_currency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Disassociation outside of app is shown', function () {
|
it('Disassociation outside of app is shown', function () {
|
||||||
cy.staking_page_associate_tokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
cy.validate_wallet_currency('Associated', '2.00');
|
cy.wrap(validateWalletCurrency('Associated', '2.00')).then(() => {
|
||||||
cy.vega_wallet_disassociate('2');
|
vegaWalletDisassociate('2');
|
||||||
|
});
|
||||||
cy.getByTestId('currency-title', txTimeout).should(
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
'have.length.above',
|
'have.length.above',
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
cy.validate_wallet_currency('Associated', '2.00');
|
validateWalletCurrency('Associated', '2.00');
|
||||||
cy.validate_wallet_currency('Pending association', '2.00');
|
validateWalletCurrency('Pending association', '2.00');
|
||||||
cy.validate_wallet_currency('Total associated after pending', '0.00');
|
validateWalletCurrency('Total associated after pending', '0.00');
|
||||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||||
cy.validate_wallet_currency('Associated', '0.00');
|
validateWalletCurrency('Associated', '0.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to associate tokens to different public key of connected vega wallet', function () {
|
it('Able to associate tokens to different public key of connected vega wallet', function () {
|
||||||
@@ -371,7 +317,7 @@ context(
|
|||||||
'have.text',
|
'have.text',
|
||||||
Cypress.env('vegaWalletPublicKey2')
|
Cypress.env('vegaWalletPublicKey2')
|
||||||
);
|
);
|
||||||
cy.staking_page_associate_tokens('2');
|
stakingPageAssociateTokens('2');
|
||||||
cy.get(vegaWallet).within(() => {
|
cy.get(vegaWallet).within(() => {
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
|
||||||
});
|
});
|
||||||
@@ -381,7 +327,7 @@ context(
|
|||||||
'vegaWalletPublicKey2Short'
|
'vegaWalletPublicKey2Short'
|
||||||
)} can now participate in governance and nominate a validator with your associated $VEGA.`
|
)} can now participate in governance and nominate a validator with your associated $VEGA.`
|
||||||
);
|
);
|
||||||
cy.staking_page_disassociate_all_tokens();
|
stakingPageDisassociateAllTokens();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+78
-49
@@ -1,5 +1,16 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
import {
|
||||||
|
depositAsset,
|
||||||
|
vegaWalletTeardown,
|
||||||
|
} from '../../support/wallet-teardown.functions';
|
||||||
|
|
||||||
const withdraw = 'withdraw';
|
const withdraw = 'withdraw';
|
||||||
const selectAsset = 'select-asset';
|
const withdrawalForm = 'withdraw-form';
|
||||||
const ethAddressInput = 'eth-address-input';
|
const ethAddressInput = 'eth-address-input';
|
||||||
const amountInput = 'amount-input';
|
const amountInput = 'amount-input';
|
||||||
const balanceAvailable = 'BALANCE_AVAILABLE_value';
|
const balanceAvailable = 'BALANCE_AVAILABLE_value';
|
||||||
@@ -17,6 +28,8 @@ const completeWithdrawalButton = 'complete-withdrawal';
|
|||||||
const usdtName = 'USDC (local)';
|
const usdtName = 'USDC (local)';
|
||||||
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
const usdcEthAddress = '0x1b8a1B6CBE5c93609b46D1829Cc7f3Cb8eeE23a0';
|
||||||
const usdcSymbol = 'tUSDC';
|
const usdcSymbol = 'tUSDC';
|
||||||
|
const usdtSelectValue =
|
||||||
|
'993ed98f4f770d91a796faab1738551193ba45c62341d20597df70fea6704ede';
|
||||||
const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
|
const truncatedWithdrawalEthAddress = '0xEe7D…22d94F';
|
||||||
const formValidationError = 'input-error-text';
|
const formValidationError = 'input-error-text';
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
@@ -26,60 +39,72 @@ context(
|
|||||||
{ tags: '@slow' },
|
{ tags: '@slow' },
|
||||||
function () {
|
function () {
|
||||||
before('visit withdrawals and connect vega wallet', function () {
|
before('visit withdrawals and connect vega wallet', function () {
|
||||||
cy.updateCapsuleMultiSig(); // When running tests locally, will fail if run without restarting capsule
|
cy.visit('/');
|
||||||
cy.deposit_asset(usdcEthAddress, '100000000000000000000');
|
// When running tests locally, will fail if run without restarting capsule
|
||||||
|
cy.updateCapsuleMultiSig().then(() => {
|
||||||
|
depositAsset(usdcEthAddress, '100');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('Navigate to withdrawal page', function () {
|
beforeEach('Navigate to withdrawal page', function () {
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.visit('/');
|
waitForSpinner();
|
||||||
cy.wait_for_spinner();
|
navigateTo(navigation.withdraw);
|
||||||
cy.navigate_to('withdraw');
|
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.vega_wallet_teardown();
|
vegaWalletTeardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to open withdrawal form with vega wallet connected', function () {
|
it('Able to open withdrawal form with vega wallet connected', function () {
|
||||||
// needs to reload page for withdrawal form to be displayed in ci - not reproducible outside of ci
|
// needs to reload page for withdrawal form to be displayed in ci - not reproducible outside of ci
|
||||||
|
cy.reload();
|
||||||
|
waitForSpinner();
|
||||||
|
ethereumWalletConnect();
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(selectAsset)
|
cy.getByTestId(withdrawalForm).within(() => {
|
||||||
.find('option')
|
cy.get('select').find('option').should('have.length.at.least', 2);
|
||||||
.should('have.length.at.least', 2);
|
cy.getByTestId(ethAddressInput).should('be.visible');
|
||||||
cy.getByTestId(ethAddressInput).should('be.visible');
|
cy.getByTestId(amountInput).should('be.visible');
|
||||||
cy.getByTestId(amountInput).should('be.visible');
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Unable to submit withdrawal with invalid fields', function () {
|
it('Unable to submit withdrawal with invalid fields', function () {
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(selectAsset).select(usdtName);
|
cy.getByTestId(withdrawalForm).within(() => {
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.get('select').select(usdtSelectValue, { force: true });
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(formValidationError).should('have.length', 1);
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
cy.getByTestId(amountInput).clear().click().type('0.0000001');
|
cy.getByTestId(formValidationError).should('have.length', 1);
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(amountInput).clear().click().type('0.0000001');
|
||||||
cy.getByTestId(formValidationError).should(
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
'have.text',
|
cy.getByTestId(formValidationError).should(
|
||||||
'Value is below minimum'
|
'have.text',
|
||||||
);
|
'Value is below minimum'
|
||||||
cy.getByTestId(amountInput).clear().click().type('10');
|
);
|
||||||
cy.getByTestId(ethAddressInput).click().type('123');
|
cy.getByTestId(amountInput).clear().click().type('10');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(ethAddressInput).click().type('123');
|
||||||
cy.getByTestId(formValidationError).should(
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
'have.text',
|
cy.getByTestId(formValidationError).should(
|
||||||
'Invalid Ethereum address'
|
'have.text',
|
||||||
);
|
'Invalid Ethereum address'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
|
it('Able to withdraw asset: -eth wallet connected -withdraw funds button', function () {
|
||||||
// fill in withdrawal form
|
// fill in withdrawal form
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(selectAsset).select(usdtName);
|
cy.getByTestId(withdrawalForm).within(() => {
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.get('select').select(usdtSelectValue, { force: true });
|
||||||
cy.getByTestId(withdrawalThreshold).should('have.text', '100,000.00000T');
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(delayTime).should('have.text', 'None');
|
cy.getByTestId(withdrawalThreshold).should(
|
||||||
cy.getByTestId(amountInput).click().type('100');
|
'have.text',
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
'100,000.00000T'
|
||||||
|
);
|
||||||
|
cy.getByTestId(delayTime).should('have.text', 'None');
|
||||||
|
cy.getByTestId(amountInput).click().type('100');
|
||||||
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
|
});
|
||||||
|
|
||||||
cy.contains('Awaiting network confirmation').should('be.visible');
|
cy.contains('Awaiting network confirmation').should('be.visible');
|
||||||
// assert withdrawal request
|
// assert withdrawal request
|
||||||
@@ -136,15 +161,17 @@ context(
|
|||||||
waitForAssetsDisplayed(usdtName);
|
waitForAssetsDisplayed(usdtName);
|
||||||
// fill in withdrawal form
|
// fill in withdrawal form
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(selectAsset).select(usdtName);
|
cy.getByTestId(withdrawalForm).within(() => {
|
||||||
cy.getByTestId(ethAddressInput).should('be.empty');
|
cy.get('select').select(usdtSelectValue, { force: true });
|
||||||
cy.getByTestId(amountInput).click().type('100');
|
cy.getByTestId(ethAddressInput).should('be.empty');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(amountInput).click().type('100');
|
||||||
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
|
|
||||||
// Need eth address to submit withdrawal
|
// Need eth address to submit withdrawal
|
||||||
cy.getByTestId(formValidationError).should('have.length', 1);
|
cy.getByTestId(formValidationError).should('have.length', 1);
|
||||||
cy.getByTestId(ethAddressInput).click().type(ethWalletAddress);
|
cy.getByTestId(ethAddressInput).click().type(ethWalletAddress);
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
|
});
|
||||||
|
|
||||||
cy.contains('Awaiting network confirmation').should('be.visible');
|
cy.contains('Awaiting network confirmation').should('be.visible');
|
||||||
// assert withdrawal request
|
// assert withdrawal request
|
||||||
@@ -180,10 +207,12 @@ context(
|
|||||||
|
|
||||||
cy.connectPublicKey(vegaWalletPubKey);
|
cy.connectPublicKey(vegaWalletPubKey);
|
||||||
cy.getByTestId(withdraw).should('be.visible').click();
|
cy.getByTestId(withdraw).should('be.visible').click();
|
||||||
cy.getByTestId(selectAsset).select(usdtName);
|
cy.getByTestId(withdrawalForm).within(() => {
|
||||||
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
cy.get('select').select(usdtSelectValue, { force: true });
|
||||||
cy.getByTestId(amountInput).click().type('100');
|
cy.getByTestId(balanceAvailable, txTimeout).should('exist');
|
||||||
cy.getByTestId(submitWithdrawalButton).click();
|
cy.getByTestId(amountInput).click().type('100');
|
||||||
|
cy.getByTestId(submitWithdrawalButton).click();
|
||||||
|
});
|
||||||
|
|
||||||
cy.getByTestId('dialog-content').within(() => {
|
cy.getByTestId('dialog-content').within(() => {
|
||||||
cy.get('h1').should('have.text', 'Transaction failed');
|
cy.get('h1').should('have.text', 'Transaction failed');
|
||||||
@@ -191,7 +220,7 @@ context(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function waitForAssetsDisplayed(expectedAsset) {
|
function waitForAssetsDisplayed(expectedAsset: string) {
|
||||||
cy.contains(expectedAsset, txTimeout).should('be.visible');
|
cy.contains(expectedAsset, txTimeout).should('be.visible');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
|
||||||
before('visit token home page', function () {
|
|
||||||
cy.visit('/');
|
|
||||||
cy.get('nav', { timeout: 10000 }).should('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with wallets disconnected', function () {
|
|
||||||
describe('Links and buttons', function () {
|
|
||||||
it('should have link for proposal page', function () {
|
|
||||||
cy.getByTestId('home-proposals').within(() => {
|
|
||||||
cy.get('[href="/proposals"]')
|
|
||||||
.should('exist')
|
|
||||||
.and('have.text', 'Browse, vote, and propose');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should show open or enacted proposals with proposal summary', function () {
|
|
||||||
cy.get('body').then(($body) => {
|
|
||||||
if (!$body.find('[data-testid="proposals-list-item"]').length) {
|
|
||||||
cy.createMarket();
|
|
||||||
cy.reload();
|
|
||||||
cy.wait_for_spinner();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cy.getByTestId('proposals-list-item')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.first()
|
|
||||||
.within(() => {
|
|
||||||
cy.getByTestId('proposal-title')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('proposal-type')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('proposal-description')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('proposal-details')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('proposal-status')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('vote-details')
|
|
||||||
.invoke('text')
|
|
||||||
.should('not.be.empty');
|
|
||||||
cy.getByTestId('view-proposal-btn').should('be.visible');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have external link for governance', function () {
|
|
||||||
cy.getByTestId('home-proposals').within(() => {
|
|
||||||
cy.getByTestId('external-link')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and('contain', 'https://vega.xyz/governance');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have link for validator page', function () {
|
|
||||||
cy.getByTestId('home-validators').within(() => {
|
|
||||||
cy.get('[href="/validators"]')
|
|
||||||
.first()
|
|
||||||
.should('exist')
|
|
||||||
.and('have.text', 'Browse, and stake');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have external link for validators', function () {
|
|
||||||
cy.getByTestId('home-validators').within(() => {
|
|
||||||
cy.getByTestId('external-link')
|
|
||||||
.should('have.attr', 'href')
|
|
||||||
.and(
|
|
||||||
'contain',
|
|
||||||
'https://community.vega.xyz/c/mainnet-validator-candidates'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have information on active nodes', function () {
|
|
||||||
cy.getByTestId('node-information')
|
|
||||||
.first()
|
|
||||||
.should('contain.text', '2')
|
|
||||||
.and('contain.text', 'active nodes');
|
|
||||||
});
|
|
||||||
it('should have information on consensus nodes', function () {
|
|
||||||
cy.getByTestId('node-information')
|
|
||||||
.last()
|
|
||||||
.should('contain.text', '2')
|
|
||||||
.and('contain.text', 'consensus nodes');
|
|
||||||
});
|
|
||||||
it('should contain link to specific validators', function () {
|
|
||||||
cy.getByTestId('validators')
|
|
||||||
.should('have.length', '2')
|
|
||||||
.each(($validator) => {
|
|
||||||
cy.wrap($validator).find('a').should('have.attr', 'href');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have link for rewards page', function () {
|
|
||||||
cy.getByTestId('home-rewards').within(() => {
|
|
||||||
cy.get('[href="/rewards"]')
|
|
||||||
.first()
|
|
||||||
.should('exist')
|
|
||||||
.and('have.text', 'See rewards');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should have link for withdrawal page', function () {
|
|
||||||
cy.getByTestId('home-vega-token').within(() => {
|
|
||||||
cy.get('[href="/token/withdraw"]')
|
|
||||||
.first()
|
|
||||||
.should('exist')
|
|
||||||
.and('have.text', 'Manage tokens');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
import { waitForSpinner } from '../../support/common.functions';
|
||||||
|
|
||||||
|
context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
|
||||||
|
before('visit token home page', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
cy.get('nav', { timeout: 10000 }).should('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Links and buttons', function () {
|
||||||
|
it('should have link for proposal page', function () {
|
||||||
|
cy.getByTestId('home-proposals').within(() => {
|
||||||
|
cy.get('[href="/proposals"]')
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Browse, vote, and propose');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display announcement banner', function () {
|
||||||
|
cy.getByTestId('app-announcement')
|
||||||
|
.should('be.visible')
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('external-link').should('exist');
|
||||||
|
});
|
||||||
|
cy.getByTestId('app-announcement-close').should('be.visible').click();
|
||||||
|
cy.getByTestId('app-announcement').should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show open or enacted proposals with proposal summary', function () {
|
||||||
|
cy.get('body').then(($body) => {
|
||||||
|
if (!$body.find('[data-testid="proposals-list-item"]').length) {
|
||||||
|
cy.createMarket();
|
||||||
|
cy.reload();
|
||||||
|
waitForSpinner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cy.getByTestId('proposals-list-item')
|
||||||
|
.should('have.length.at.least', 1)
|
||||||
|
.first()
|
||||||
|
.within(() => {
|
||||||
|
cy.getByTestId('proposal-title')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
cy.getByTestId('proposal-type').invoke('text').should('not.be.empty');
|
||||||
|
cy.getByTestId('proposal-description')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
cy.getByTestId('proposal-details')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
cy.getByTestId('proposal-status')
|
||||||
|
.invoke('text')
|
||||||
|
.should('not.be.empty');
|
||||||
|
cy.getByTestId('vote-details').invoke('text').should('not.be.empty');
|
||||||
|
cy.getByTestId('view-proposal-btn').should('be.visible');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have external link for governance', function () {
|
||||||
|
cy.getByTestId('home-proposals').within(() => {
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', 'https://vega.xyz/governance');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have link for validator page', function () {
|
||||||
|
cy.getByTestId('home-validators').within(() => {
|
||||||
|
cy.get('[href="/validators"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Browse, and stake');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have external link for validators', function () {
|
||||||
|
cy.getByTestId('home-validators').within(() => {
|
||||||
|
cy.getByTestId('external-link')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and(
|
||||||
|
'contain',
|
||||||
|
'https://community.vega.xyz/c/mainnet-validator-candidates'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have information on active nodes', function () {
|
||||||
|
cy.getByTestId('node-information')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', '2')
|
||||||
|
.and('contain.text', 'active nodes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have information on consensus nodes', function () {
|
||||||
|
cy.getByTestId('node-information')
|
||||||
|
.last()
|
||||||
|
.should('contain.text', '2')
|
||||||
|
.and('contain.text', 'consensus nodes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain link to specific validators', function () {
|
||||||
|
cy.getByTestId('validators')
|
||||||
|
.should('have.length', '2')
|
||||||
|
.each(($validator) => {
|
||||||
|
cy.wrap($validator).find('a').should('have.attr', 'href');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have link for rewards page', function () {
|
||||||
|
cy.getByTestId('home-rewards').within(() => {
|
||||||
|
cy.get('[href="/rewards"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'See rewards');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have link for withdrawal page', function () {
|
||||||
|
cy.getByTestId('home-vega-token').within(() => {
|
||||||
|
cy.get('[href="/token/withdraw"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Manage tokens');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display network data', function () {
|
||||||
|
cy.getByTestId('git-network-data')
|
||||||
|
.should('contain.text', 'Reading network data from')
|
||||||
|
.within(() => {
|
||||||
|
cy.get('span')
|
||||||
|
.first()
|
||||||
|
.should('have.text', 'http://localhost:3028/query');
|
||||||
|
cy.getByTestId('link').should('exist');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display eth data', function () {
|
||||||
|
cy.getByTestId('git-eth-data')
|
||||||
|
.should('contain.text', 'Reading Ethereum data from')
|
||||||
|
.within(() => {
|
||||||
|
cy.get('span').should('have.text', 'http://localhost:8545');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain link for known issues on Github', function () {
|
||||||
|
cy.getByTestId('git-info').within(() => {
|
||||||
|
cy.contains('Known issues and feedback on')
|
||||||
|
.find('[data-testid="link"]')
|
||||||
|
.should(
|
||||||
|
'have.attr',
|
||||||
|
'href',
|
||||||
|
'https://github.com/vegaprotocol/feedback/discussions'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Mobile view - navigation bar', function () {
|
||||||
|
before('Change to mobile resolution', function () {
|
||||||
|
cy.viewport('iphone-xr');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have burger button', () => {
|
||||||
|
cy.getByTestId('button-menu-drawer').should('be.visible').click();
|
||||||
|
cy.getByTestId('menu-drawer').should('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have link for proposal page', function () {
|
||||||
|
cy.getByTestId('menu-drawer').within(() => {
|
||||||
|
cy.get('[href="/proposals"]')
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Proposals');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should have link for validator page', function () {
|
||||||
|
cy.getByTestId('menu-drawer').within(() => {
|
||||||
|
cy.get('[href="/validators"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Validators');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have link for rewards page', function () {
|
||||||
|
cy.getByTestId('menu-drawer').within(() => {
|
||||||
|
cy.get('[href="/rewards"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Rewards');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should have link for withdrawal page', function () {
|
||||||
|
cy.getByTestId('menu-drawer').within(() => {
|
||||||
|
cy.get('[href="/token/withdraw"]')
|
||||||
|
.first()
|
||||||
|
.should('exist')
|
||||||
|
.and('have.text', 'Withdraw');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
cy.viewport(
|
||||||
|
Cypress.config('viewportWidth'),
|
||||||
|
Cypress.config('viewportHeight')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
context(
|
|
||||||
'Landing pages - verifies required elements',
|
|
||||||
{ tags: '@smoke' },
|
|
||||||
() => {
|
|
||||||
const navbar = 'nav .navbar';
|
|
||||||
const mobileNav = '[data-testid="menu-drawer"]';
|
|
||||||
|
|
||||||
const topLevelLinks = [
|
|
||||||
{
|
|
||||||
name: 'Proposals',
|
|
||||||
selector: '[href="/proposals"]',
|
|
||||||
tests: () => {
|
|
||||||
it('should be able to see a working link for - find out more about Vega governance', function () {
|
|
||||||
const governanceDocsUrl = 'https://vega.xyz/governance';
|
|
||||||
const proposalDocumentationLink =
|
|
||||||
'[data-testid="proposal-documentation-link"]';
|
|
||||||
// 3001-VOTE-001
|
|
||||||
cy.get(proposalDocumentationLink)
|
|
||||||
.should('be.visible')
|
|
||||||
.and('have.text', 'Find out more about Vega governance')
|
|
||||||
.and('have.attr', 'href')
|
|
||||||
.and('equal', governanceDocsUrl);
|
|
||||||
|
|
||||||
// 3002-PROP-001
|
|
||||||
cy.request(governanceDocsUrl)
|
|
||||||
.its('body')
|
|
||||||
.then((body) => {
|
|
||||||
if (!body.includes('Govern the network')) {
|
|
||||||
assert.include(
|
|
||||||
body,
|
|
||||||
'Govern the network',
|
|
||||||
`Checking that governance link destination includes 'Govern the network' text`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to see button for - new proposal', function () {
|
|
||||||
// 3001-VOTE-002
|
|
||||||
const newProposalLink = '[data-testid="new-proposal-link"]';
|
|
||||||
cy.get(newProposalLink)
|
|
||||||
.should('be.visible')
|
|
||||||
.and('have.text', 'New proposal')
|
|
||||||
.and('have.attr', 'href')
|
|
||||||
.and('equal', '/proposals/propose');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Validators',
|
|
||||||
selector: '[href="/validators"]',
|
|
||||||
tests: () => {
|
|
||||||
it('Should have Staking Guide link visible', function () {
|
|
||||||
// 2001-STKE-003
|
|
||||||
cy.get('[data-testid="staking-guide-link"]')
|
|
||||||
.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'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Rewards',
|
|
||||||
selector: '[href="/rewards"]',
|
|
||||||
header: 'Rewards and fees',
|
|
||||||
tests: () => {
|
|
||||||
it('should have epoch warning', () => {
|
|
||||||
cy.get('[data-testid="callout"]')
|
|
||||||
.should('be.visible')
|
|
||||||
.and(
|
|
||||||
'have.text',
|
|
||||||
'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('should have toggle for seeing total vs individual rewards', () => {
|
|
||||||
cy.get('[data-testid="epoch-reward-view-toggle-total"]').should(
|
|
||||||
'be.visible'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const secondLevelLinks = [
|
|
||||||
{
|
|
||||||
trigger: true,
|
|
||||||
name: 'Token',
|
|
||||||
selector: '[data-testid="state-trigger"]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Token',
|
|
||||||
selector: '[href="/token"]',
|
|
||||||
header: 'The $VEGA token',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Supply & Vesting',
|
|
||||||
selector: '[href="/token/tranches"]',
|
|
||||||
header: 'Vesting tranches',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Withdraw',
|
|
||||||
selector: '[href="/token/withdraw"]',
|
|
||||||
header: 'Withdrawals',
|
|
||||||
tests: () => {
|
|
||||||
it('should have connect Vega wallet button', function () {
|
|
||||||
cy.get('[data-testid="connect-to-vega-wallet-btn"]')
|
|
||||||
.should('be.visible')
|
|
||||||
.and('have.text', 'Connect Vega wallet');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Redeem',
|
|
||||||
selector: '[href="/token/redeem"]',
|
|
||||||
header: 'Vesting',
|
|
||||||
tests: () => {
|
|
||||||
// 1005-VEST-018
|
|
||||||
it('should have connect Eth wallet button', function () {
|
|
||||||
cy.get('[data-testid="connect-to-eth-btn"]')
|
|
||||||
.should('be.visible')
|
|
||||||
.and('have.text', 'Connect Ethereum wallet');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Associate',
|
|
||||||
selector: '[href="/token/associate"]',
|
|
||||||
header: 'Associate $VEGA tokens with Vega Key',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Disassociate',
|
|
||||||
selector: '[href="/token/disassociate"]',
|
|
||||||
header: 'Disassociate $VEGA tokens from a Vega key',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const expand = () => {
|
|
||||||
const trigger = secondLevelLinks.find((l) => l.trigger).selector;
|
|
||||||
cy.get(trigger).then((el) => {
|
|
||||||
if (el.attr('aria-expanded') === 'false') {
|
|
||||||
el.trigger('click');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const collapse = () => {
|
|
||||||
const trigger = secondLevelLinks.find((l) => l.trigger).selector;
|
|
||||||
cy.get(trigger).then((el) => {
|
|
||||||
if (el.attr('aria-expanded') === 'true') {
|
|
||||||
el.trigger('click');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const ensureHeader = (text) => {
|
|
||||||
cy.get('main header h1').should('have.text', text);
|
|
||||||
};
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
// goes to HOME
|
|
||||||
cy.visit('/');
|
|
||||||
// and waits for it to load
|
|
||||||
cy.get(navbar, { timeout: 10000 }).should('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Navigation (desktop)', () => {
|
|
||||||
for (const { name, selector } of topLevelLinks) {
|
|
||||||
it(`should have ${name} nav link`, () => {
|
|
||||||
cy.get(navbar).within(() => {
|
|
||||||
cy.get(selector).should('be.visible');
|
|
||||||
cy.get(selector).should('have.text', name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const { name, selector, trigger } of secondLevelLinks) {
|
|
||||||
it(`should have ${name} ${
|
|
||||||
trigger ? 'as trigger button' : ''
|
|
||||||
} second level nav link`, () => {
|
|
||||||
cy.get(navbar).within(() => {
|
|
||||||
cy.get(selector).should('be.visible');
|
|
||||||
cy.get(selector).should('have.text', name);
|
|
||||||
if (trigger) cy.get(selector).click();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
collapse();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Navigation (mobile)', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// iphone xr
|
|
||||||
cy.viewport(414, 896);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have burger button', () => {
|
|
||||||
cy.get('[data-testid="button-menu-drawer"]').should('be.visible');
|
|
||||||
cy.get('[data-testid="button-menu-drawer"]').click();
|
|
||||||
cy.get(mobileNav).should('be.visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const { name, selector } of topLevelLinks) {
|
|
||||||
it(`should have ${name} nav link`, () => {
|
|
||||||
cy.get(mobileNav).within(() => {
|
|
||||||
cy.get(selector).should('be.visible');
|
|
||||||
cy.get(selector).should('have.text', name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const { name, selector, trigger } of secondLevelLinks) {
|
|
||||||
it(`should have ${name} ${
|
|
||||||
trigger ? 'as trigger button' : ''
|
|
||||||
} second level nav link`, () => {
|
|
||||||
cy.get(mobileNav).within(() => {
|
|
||||||
cy.get(selector).should('be.visible');
|
|
||||||
cy.get(selector).should('have.text', name);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
cy.get('[data-testid="button-menu-drawer"]').click();
|
|
||||||
cy.viewport(
|
|
||||||
Cypress.config('viewportWidth'),
|
|
||||||
Cypress.config('viewportHeight')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Elements', () => {
|
|
||||||
for (const { name, selector, header, tests } of topLevelLinks) {
|
|
||||||
describe(`${name} page`, () => {
|
|
||||||
it(`navigates to ${name}`, () => {
|
|
||||||
cy.get(navbar).within(() => {
|
|
||||||
cy.log(`goes to ${name}`);
|
|
||||||
cy.get(selector).click();
|
|
||||||
cy.log(`ensures ${name} is highlighted`);
|
|
||||||
cy.get(selector).should('have.attr', 'aria-current');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('displays header', () => {
|
|
||||||
ensureHeader(header || name);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tests) tests.apply(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const { name, selector, header, tests } of secondLevelLinks.filter(
|
|
||||||
(l) => !l.trigger
|
|
||||||
)) {
|
|
||||||
describe(`${name} page`, () => {
|
|
||||||
it(`navigates to ${name}`, () => {
|
|
||||||
cy.get(navbar).within(() => {
|
|
||||||
expand();
|
|
||||||
cy.log(`goes to ${name}`);
|
|
||||||
cy.get(selector).click();
|
|
||||||
expand();
|
|
||||||
cy.log(`ensures ${name} is highlighted`);
|
|
||||||
cy.get(selector).should('have.attr', 'aria-current');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('displays header', () => {
|
|
||||||
ensureHeader(header || name);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tests) tests.apply(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
collapse();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
verifyPageHeader,
|
||||||
|
verifyTabHighlighted,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
|
||||||
|
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
|
||||||
|
const newProposalButton = '[data-testid="new-proposal-link"]';
|
||||||
|
const newProposalLink = '[data-testid="new-proposal-link"]';
|
||||||
|
const governanceDocsUrl = 'https://vega.xyz/governance';
|
||||||
|
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||||
|
|
||||||
|
context(
|
||||||
|
'Governance Page - verify elements on page',
|
||||||
|
{ tags: '@smoke' },
|
||||||
|
function () {
|
||||||
|
before('navigate to governance page', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with no network change proposals', function () {
|
||||||
|
it('should have governance tab highlighted', function () {
|
||||||
|
verifyTabHighlighted(navigation.proposals);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have GOVERNANCE header visible', function () {
|
||||||
|
verifyPageHeader('Proposals');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to see a working link for - find out more about Vega governance', function () {
|
||||||
|
// 3001-VOTE-001
|
||||||
|
cy.get(proposalDocumentationLink)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'Find out more about Vega governance')
|
||||||
|
.and('have.attr', 'href')
|
||||||
|
.and('equal', governanceDocsUrl);
|
||||||
|
|
||||||
|
// 3002-PROP-001
|
||||||
|
cy.request(governanceDocsUrl)
|
||||||
|
.its('body')
|
||||||
|
.then((body) => {
|
||||||
|
if (!body.includes('Govern the network')) {
|
||||||
|
assert.include(
|
||||||
|
body,
|
||||||
|
'Govern the network',
|
||||||
|
`Checking that governance link destination includes 'Govern the network' text`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to see button for - new proposal', function () {
|
||||||
|
// 3001-VOTE-002
|
||||||
|
cy.get(newProposalLink)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'New proposal')
|
||||||
|
.and('have.attr', 'href')
|
||||||
|
.and('equal', '/proposals/propose');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Skipping this test for now, the new proposal button no longer takes a user directly
|
||||||
|
// to a proposal form, instead it takes them to a page where they can select a proposal type.
|
||||||
|
// Keeping this test here for now as it can be repurposed to test the new proposal forms.
|
||||||
|
it.skip('should be able to see a connect wallet button - if vega wallet disconnected and new proposal button selected', function () {
|
||||||
|
cy.get(newProposalButton).should('be.visible').click();
|
||||||
|
cy.get(connectToVegaWalletButton)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'Connect Vega wallet');
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
waitForSpinner();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
+24
-17
@@ -1,43 +1,50 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
waitForSpinner,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import {
|
||||||
|
enterUniqueFreeFormProposalBody,
|
||||||
|
goToMakeNewProposal,
|
||||||
|
} from '../../support/governance.functions';
|
||||||
|
import { vegaWalletFaucetAssetsWithoutCheck } from '../../support/wallet-vega.functions';
|
||||||
|
|
||||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
|
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey2');
|
||||||
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
|
const vegaPubkeyTruncated = Cypress.env('vegaWalletPublicKey2Short');
|
||||||
const banner = 'view-banner';
|
const banner = 'view-banner';
|
||||||
|
|
||||||
context('View functionality with public key', { tags: '@smoke' }, function () {
|
context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||||
before('send asset to wallet', function () {
|
before('send asset to wallet', function () {
|
||||||
cy.vega_wallet_faucet_assets_without_check(
|
vegaWalletFaucetAssetsWithoutCheck('fUSDC', '1000000', vegaWalletPubKey);
|
||||||
'fUSDC',
|
|
||||||
'1000000',
|
|
||||||
vegaWalletPubKey
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach('visit home page', function () {
|
beforeEach('visit home page', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectPublicKey(vegaWalletPubKey);
|
cy.connectPublicKey(vegaWalletPubKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Able to connect public key via wallet', function () {
|
|
||||||
verifyConnectedToPubKey();
|
|
||||||
cy.getByTestId('currency-title', Cypress.env('epochTimeout')).should(
|
|
||||||
'contain.text',
|
|
||||||
'USDC (fake)'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Able to connect public key using url', function () {
|
it('Able to connect public key using url', function () {
|
||||||
cy.getByTestId('exit-view').click();
|
cy.getByTestId('exit-view').click();
|
||||||
cy.visit(`/?address=${vegaWalletPubKey}`);
|
cy.visit(`/?address=${vegaWalletPubKey}`);
|
||||||
verifyConnectedToPubKey();
|
verifyConnectedToPubKey();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Able to connect public key via wallet and view assets in wallet', function () {
|
||||||
|
verifyConnectedToPubKey();
|
||||||
|
cy.getByTestId('currency-title', { timeout: 10000 })
|
||||||
|
.should('have.length.at.least', 4)
|
||||||
|
.and('contain.text', 'USDC (fake)');
|
||||||
|
});
|
||||||
|
|
||||||
it('Unable to submit proposal with public key', function () {
|
it('Unable to submit proposal with public key', function () {
|
||||||
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
const expectedErrorTxt = `You are connected in a view only state for public key: ${vegaWalletPubKey}. In order to send transactions you must connect to a real wallet.`;
|
||||||
|
|
||||||
cy.navigate_to('proposals');
|
navigateTo(navigation.proposals);
|
||||||
cy.go_to_make_new_proposal('Freeform');
|
goToMakeNewProposal('Freeform');
|
||||||
cy.enter_unique_freeform_proposal_body('50', 'pub key proposal test');
|
enterUniqueFreeFormProposalBody('50', 'pub key proposal test');
|
||||||
cy.getByTestId('dialog-content').within(() => {
|
cy.getByTestId('dialog-content').within(() => {
|
||||||
cy.get('h1').should('have.text', 'Transaction failed');
|
cy.get('h1').should('have.text', 'Transaction failed');
|
||||||
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
|
cy.getByTestId('Error').should('have.text', expectedErrorTxt);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
verifyPageHeader,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
|
||||||
|
const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
|
||||||
|
const warning = '[data-testid="callout"]';
|
||||||
|
|
||||||
|
context(
|
||||||
|
'Rewards Page - verify elements on page',
|
||||||
|
{ tags: '@regression' },
|
||||||
|
function () {
|
||||||
|
before('navigate to rewards page', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.rewards);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with wallets disconnected', function () {
|
||||||
|
it('should have REWARDS tab highlighted', function () {
|
||||||
|
verifyPageHeader('Rewards and fees');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have rewards header visible', function () {
|
||||||
|
verifyPageHeader('Rewards and fees');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have epoch warning', function () {
|
||||||
|
cy.get(warning)
|
||||||
|
.should('be.visible')
|
||||||
|
.and(
|
||||||
|
'have.text',
|
||||||
|
'Rewards are credited less than a minute after the epoch ends.This delay is set by a network parameter'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have toggle for seeing total vs individual rewards', function () {
|
||||||
|
cy.get(viewToggle).should('be.visible');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
+4
-1
@@ -1,3 +1,5 @@
|
|||||||
|
import { navigateTo, navigation } from '../../support/common.functions';
|
||||||
|
|
||||||
const tokenDetailsTable = '.token-details';
|
const tokenDetailsTable = '.token-details';
|
||||||
const address = '[data-testid="token-address"]';
|
const address = '[data-testid="token-address"]';
|
||||||
const contract = '[data-testid="token-contract"]';
|
const contract = '[data-testid="token-contract"]';
|
||||||
@@ -17,7 +19,8 @@ const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
|||||||
|
|
||||||
context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
context('Verify elements on Token page', { tags: '@smoke' }, function () {
|
||||||
before('Visit token page', function () {
|
before('Visit token page', function () {
|
||||||
cy.visit('/token');
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.token);
|
||||||
});
|
});
|
||||||
describe('THE $VEGA TOKEN table', function () {
|
describe('THE $VEGA TOKEN table', function () {
|
||||||
it('should have TOKEN ADDRESS', function () {
|
it('should have TOKEN ADDRESS', function () {
|
||||||
+9
-2
@@ -1,4 +1,5 @@
|
|||||||
import { trancheData } from '../../fixtures/mocks/tranches';
|
import { trancheData } from '../../fixtures/mocks/tranches';
|
||||||
|
import { navigateTo, navigation } from '../../support/common.functions';
|
||||||
|
|
||||||
const tranches = trancheData;
|
const tranches = trancheData;
|
||||||
|
|
||||||
@@ -8,7 +9,13 @@ context(
|
|||||||
function () {
|
function () {
|
||||||
before('visit homepage', function () {
|
before('visit homepage', function () {
|
||||||
cy.intercept('GET', '**/tranches/stats', { tranches });
|
cy.intercept('GET', '**/tranches/stats', { tranches });
|
||||||
cy.visit('/token/tranches');
|
cy.visit('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Able to navigate to tranches page', function () {
|
||||||
|
navigateTo(navigation.supply);
|
||||||
|
cy.url().should('include', '/token/tranches');
|
||||||
|
cy.get('h1').should('contain.text', 'Vesting tranches');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1005-VEST-001
|
// 1005-VEST-001
|
||||||
@@ -62,7 +69,7 @@ context(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Able to view tranches with less than 10 vega', function () {
|
it('Able to view tranches with less than 10 vega', function () {
|
||||||
cy.navigate_to('supply');
|
navigateTo(navigation.supply);
|
||||||
cy.getByTestId('show-all-tranches').click();
|
cy.getByTestId('show-all-tranches').click();
|
||||||
cy.getByTestId('tranche-item')
|
cy.getByTestId('tranche-item')
|
||||||
.should('have.length', 8)
|
.should('have.length', 8)
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
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 stakeNumberRegex = /^\d*\.?\d*$/;
|
|
||||||
|
|
||||||
context('Staking Page - verify elements on page', function () {
|
|
||||||
before('navigate to staking page', function () {
|
|
||||||
cy.visit('/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.get('[col-id="stake"] > div > span > span')
|
|
||||||
.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 () {
|
|
||||||
cy.get('[col-id="stake"] > div > span > span').first().realHover();
|
|
||||||
|
|
||||||
cy.get(stakedByOperatorToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Staked by operator: 0.00');
|
|
||||||
cy.get(stakedByDelegatesToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Staked by delegates: 0.00');
|
|
||||||
cy.get(totalStakedToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Total stake: 0.00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator normalised voting power', function () {
|
|
||||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
|
||||||
.should('have.length.at.least', 1)
|
|
||||||
.each(($vPower) => {
|
|
||||||
cy.wrap($vPower).should('not.be.empty');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator voting power tooltip', function () {
|
|
||||||
cy.get('[col-id="normalisedVotingPower"] > div > span > span')
|
|
||||||
.first()
|
|
||||||
.realHover();
|
|
||||||
|
|
||||||
cy.get(unnormalisedVotingPowerToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Unnormalised voting power: 0.00%');
|
|
||||||
cy.get(normalisedVotingPowerToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Normalised voting power: 0.10%');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2002-SINC-018
|
|
||||||
it('Should be able to see validator total penalties', function () {
|
|
||||||
cy.get('[col-id="totalPenalties"] > div > span > span')
|
|
||||||
.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.get('[col-id="totalPenalties"] > div > span > span').realHover();
|
|
||||||
|
|
||||||
cy.get(performancePenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Performance penalty: 100.00%');
|
|
||||||
cy.get(overstakedPenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Overstaked penalty:'); // value not asserted due to #2886
|
|
||||||
cy.get(totalPenaltyToolTip)
|
|
||||||
.invoke('text')
|
|
||||||
.should('contain', 'Total penalties: 0.00%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to see validator pending stake', function () {
|
|
||||||
cy.get('[col-id="pendingStake"] > div > span')
|
|
||||||
.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();
|
|
||||||
cy.click_on_validator_from_list(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');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
verifyPageHeader,
|
||||||
|
verifyTabHighlighted,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import { clickOnValidatorFromList } from '../../support/staking.functions';
|
||||||
|
|
||||||
|
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 stakeNumberRegex = /^\d*\.?\d*$/;
|
||||||
|
|
||||||
|
context('Validators Page - verify elements on page', function () {
|
||||||
|
before('navigate to validators page', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.validators);
|
||||||
|
});
|
||||||
|
|
||||||
|
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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
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 be able to see validator stake tooltip', function () {
|
||||||
|
cy.getByTestId('total-stake').first().realHover();
|
||||||
|
|
||||||
|
cy.get(stakedByOperatorToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Staked by operator: 0.00');
|
||||||
|
cy.get(stakedByDelegatesToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Staked by delegates: 0.00');
|
||||||
|
cy.get(totalStakedToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Total stake: 0.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: 0.00%');
|
||||||
|
cy.get(normalisedVotingPowerToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Normalised voting power: 0.10%');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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: 100.00%');
|
||||||
|
cy.get(overstakedPenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Overstaked penalty:'); // value not asserted due to #2886
|
||||||
|
cy.get(totalPenaltyToolTip)
|
||||||
|
.invoke('text')
|
||||||
|
.should('contain', 'Total penalties: 0.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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
+29
-3
@@ -1,3 +1,12 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
verifyPageHeader,
|
||||||
|
verifyTabHighlighted,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
|
||||||
|
const connectButton = '[data-testid="connect-to-eth-btn"]';
|
||||||
const lockedTokensInVestingContract = '6,499,972.30';
|
const lockedTokensInVestingContract = '6,499,972.30';
|
||||||
|
|
||||||
context(
|
context(
|
||||||
@@ -5,12 +14,30 @@ context(
|
|||||||
{ tags: '@smoke' },
|
{ tags: '@smoke' },
|
||||||
function () {
|
function () {
|
||||||
before('navigate to vesting page', function () {
|
before('navigate to vesting page', function () {
|
||||||
cy.visit('/token/redeem');
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.vesting);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with wallets disconnected', function () {
|
||||||
|
it('should have vesting tab highlighted', function () {
|
||||||
|
verifyTabHighlighted(navigation.vesting);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have VESTING header visible', function () {
|
||||||
|
verifyPageHeader('Vesting');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1005-VEST-018
|
||||||
|
it('should have connect Eth wallet button', function () {
|
||||||
|
cy.get(connectButton)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'Connect Ethereum wallet');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('With Eth wallet connected', function () {
|
describe('With Eth wallet connected', function () {
|
||||||
before('connect eth wallet', function () {
|
before('connect eth wallet', function () {
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
cy.getByTestId('view-connected-eth-btn').click();
|
cy.getByTestId('view-connected-eth-btn').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +132,6 @@ context(
|
|||||||
'All the tokens in this tranche are locked and can not be redeemed yet.'
|
'All the tokens in this tranche are locked and can not be redeemed yet.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cy.connectVegaWallet();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+25
-16
@@ -1,3 +1,6 @@
|
|||||||
|
import { convertTokenValueToNumber } from '../../support/common.functions';
|
||||||
|
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
|
||||||
|
|
||||||
const walletContainer = 'aside [data-testid="ethereum-wallet"]';
|
const walletContainer = 'aside [data-testid="ethereum-wallet"]';
|
||||||
const walletHeader = '[data-testid="wallet-header"] h1';
|
const walletHeader = '[data-testid="wallet-header"] h1';
|
||||||
const connectToEthButton =
|
const connectToEthButton =
|
||||||
@@ -87,7 +90,7 @@ context(
|
|||||||
// 0004-EWAL-001 0004-EWAL-002
|
// 0004-EWAL-001 0004-EWAL-002
|
||||||
describe('when Ethereum wallet connected', function () {
|
describe('when Ethereum wallet connected', function () {
|
||||||
before('connect to Ethereum wallet', function () {
|
before('connect to Ethereum wallet', function () {
|
||||||
cy.ethereum_wallet_connect();
|
ethereumWalletConnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have ETHEREUM KEY header visible', function () {
|
it('should have ETHEREUM KEY header visible', function () {
|
||||||
@@ -178,22 +181,25 @@ context(
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(currencyValue)
|
cy.get(currencyValue)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyValueTxt) => {
|
||||||
.as('value');
|
convertTokenValueToNumber(currencyValueTxt).as('value');
|
||||||
|
});
|
||||||
cy.get(currencyLocked)
|
cy.get(currencyLocked)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyLockedTxt) => {
|
||||||
.as('locked');
|
convertTokenValueToNumber(currencyLockedTxt).as('locked');
|
||||||
|
});
|
||||||
cy.get(currencyUnlocked)
|
cy.get(currencyUnlocked)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyUnlockedTxt) => {
|
||||||
.as('unlocked');
|
convertTokenValueToNumber(currencyUnlockedTxt).as('unlocked');
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
expect(parseFloat(this.value).toFixed(1)).to.equal(
|
expect(parseFloat(this.value).toFixed(1)).to.equal(
|
||||||
parseFloat(
|
(Math.round((this.locked + this.unlocked) * 100) / 100).toFixed(
|
||||||
Math.round((this.locked + this.unlocked) * 100) / 100
|
1
|
||||||
).toFixed(1)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -247,16 +253,19 @@ context(
|
|||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(currencyValue)
|
cy.get(currencyValue)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyValueTxt) => {
|
||||||
.as('value');
|
convertTokenValueToNumber(currencyValueTxt).as('value');
|
||||||
|
});
|
||||||
cy.get(currencyLocked)
|
cy.get(currencyLocked)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyLockedTxt) => {
|
||||||
.as('locked');
|
convertTokenValueToNumber(currencyLockedTxt).as('locked');
|
||||||
|
});
|
||||||
cy.get(currencyUnlocked)
|
cy.get(currencyUnlocked)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.convert_token_value_to_number()
|
.then((currencyUnlockedTxt) => {
|
||||||
.as('unlocked');
|
convertTokenValueToNumber(currencyUnlockedTxt).as('unlocked');
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
expect(this.value).to.equal(this.locked + this.unlocked);
|
expect(this.value).to.equal(this.locked + this.unlocked);
|
||||||
+23
-13
@@ -1,4 +1,7 @@
|
|||||||
import { truncateByChars } from '@vegaprotocol/utils';
|
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';
|
||||||
|
|
||||||
const walletContainer = 'aside [data-testid="vega-wallet"]';
|
const walletContainer = 'aside [data-testid="vega-wallet"]';
|
||||||
const walletHeader = '[data-testid="wallet-header"] h1';
|
const walletHeader = '[data-testid="wallet-header"] h1';
|
||||||
@@ -129,7 +132,7 @@ context(
|
|||||||
before('connect vega wallet', function () {
|
before('connect vega wallet', function () {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.vega_wallet_teardown();
|
vegaWalletTeardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 0002-WCON-007
|
// 0002-WCON-007
|
||||||
@@ -158,7 +161,7 @@ context(
|
|||||||
cy.get(walletContainer).within(() => {
|
cy.get(walletContainer).within(() => {
|
||||||
cy.get(currencyTitle)
|
cy.get(currencyTitle)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.and('have.text', `VEGAAssociated`);
|
.and('contain.text', `VEGAAssociated`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -167,14 +170,19 @@ context(
|
|||||||
{ tags: '@smoke' },
|
{ tags: '@smoke' },
|
||||||
function () {
|
function () {
|
||||||
cy.get(walletContainer).within(() => {
|
cy.get(walletContainer).within(() => {
|
||||||
cy.get(currencyValue).should('be.visible').and('have.text', `0.00`);
|
cy.get(currencyValue)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('contain.text', `0.00`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('should have Unstaked value visible', { tags: '@smoke' }, function () {
|
it('should have Unstaked value visible', { tags: '@smoke' }, function () {
|
||||||
cy.get(walletContainer).within(() => {
|
cy.get(walletContainer).within(() => {
|
||||||
cy.get(vegaUnstaked).should('be.visible').and('have.text', `0.00`);
|
cy.get(vegaUnstaked)
|
||||||
|
.should('be.visible')
|
||||||
|
.invoke('text')
|
||||||
|
.and('not.be.empty');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -300,16 +308,17 @@ context(
|
|||||||
|
|
||||||
before('faucet assets to connected vega wallet', function () {
|
before('faucet assets to connected vega wallet', function () {
|
||||||
for (const { id, amount } of assets) {
|
for (const { id, amount } of assets) {
|
||||||
cy.vega_wallet_faucet_assets_without_check(
|
vegaWalletFaucetAssetsWithoutCheck(id, amount, vegaWalletPublicKey);
|
||||||
id,
|
|
||||||
amount,
|
|
||||||
vegaWalletPublicKey
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.wait_for_spinner();
|
waitForSpinner();
|
||||||
cy.connectVegaWallet();
|
cy.connectVegaWallet();
|
||||||
cy.ethereum_wallet_connect();
|
cy.get(walletContainer).within(() => {
|
||||||
|
cy.getByTestId('currency-title', txTimeout).should(
|
||||||
|
'have.length.at.least',
|
||||||
|
5
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const { id, name, expectedAmount } of assets) {
|
for (const { id, name, expectedAmount } of assets) {
|
||||||
@@ -323,8 +332,9 @@ context(
|
|||||||
.contains(id)
|
.contains(id)
|
||||||
.parent()
|
.parent()
|
||||||
.siblings()
|
.siblings()
|
||||||
.within((el) => {
|
.invoke('text')
|
||||||
const value = parseFloat(el.text());
|
.then((el) => {
|
||||||
|
const value = parseFloat(el);
|
||||||
cy.wrap(value).should('be.gte', parseFloat(expectedAmount));
|
cy.wrap(value).should('be.gte', parseFloat(expectedAmount));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import {
|
||||||
|
navigateTo,
|
||||||
|
navigation,
|
||||||
|
verifyPageHeader,
|
||||||
|
verifyTabHighlighted,
|
||||||
|
} from '../../support/common.functions';
|
||||||
|
|
||||||
|
const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]';
|
||||||
|
|
||||||
|
context(
|
||||||
|
'Withdraw Page - verify elements on page',
|
||||||
|
{ tags: '@smoke' },
|
||||||
|
function () {
|
||||||
|
before('navigate to withdrawals page', function () {
|
||||||
|
cy.visit('/');
|
||||||
|
navigateTo(navigation.withdraw);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with wallets disconnected', function () {
|
||||||
|
it('should have withdraw tab highlighted', function () {
|
||||||
|
verifyTabHighlighted(navigation.withdraw);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have WITHDRAW header visible', function () {
|
||||||
|
verifyPageHeader('Withdrawals');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have connect Vega wallet button', function () {
|
||||||
|
cy.get(connectToVegaBtn)
|
||||||
|
.should('be.visible')
|
||||||
|
.and('have.text', 'Connect Vega wallet');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
export interface testFreeformProposal {
|
||||||
|
rationale: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
terms: {
|
||||||
|
closingTimestamp: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface networkParameters {
|
||||||
|
'blockchains.ethereumConfig': string;
|
||||||
|
'governance.proposal.asset.maxClose': string;
|
||||||
|
'governance.proposal.asset.maxEnact': string;
|
||||||
|
'governance.proposal.asset.minClose': string;
|
||||||
|
'governance.proposal.asset.minEnact': string;
|
||||||
|
'governance.proposal.asset.minProposerBalance': string;
|
||||||
|
'governance.proposal.asset.minVoterBalance': string;
|
||||||
|
'governance.proposal.asset.requiredMajority': string;
|
||||||
|
'governance.proposal.asset.requiredParticipation': string;
|
||||||
|
'governance.proposal.freeform.maxClose': string;
|
||||||
|
'governance.proposal.freeform.minClose': string;
|
||||||
|
'governance.proposal.freeform.minProposerBalance': string;
|
||||||
|
'governance.proposal.freeform.minVoterBalance': string;
|
||||||
|
'governance.proposal.freeform.requiredMajority': string;
|
||||||
|
'governance.proposal.freeform.requiredParticipation': string;
|
||||||
|
'governance.proposal.market.maxClose': string;
|
||||||
|
'governance.proposal.market.maxEnact': string;
|
||||||
|
'governance.proposal.market.minClose': string;
|
||||||
|
'governance.proposal.market.minEnact': string;
|
||||||
|
'governance.proposal.market.minProposerBalance': string;
|
||||||
|
'governance.proposal.market.minVoterBalance': string;
|
||||||
|
'governance.proposal.market.requiredMajority': string;
|
||||||
|
'governance.proposal.market.requiredParticipation': string;
|
||||||
|
'governance.proposal.updateAsset.maxClose': string;
|
||||||
|
'governance.proposal.updateAsset.maxEnact': string;
|
||||||
|
'governance.proposal.updateAsset.minClose': string;
|
||||||
|
'governance.proposal.updateAsset.minEnact': string;
|
||||||
|
'governance.proposal.updateAsset.minProposerBalance': string;
|
||||||
|
'governance.proposal.updateAsset.minVoterBalance': string;
|
||||||
|
'governance.proposal.updateAsset.requiredMajority': string;
|
||||||
|
'governance.proposal.updateAsset.requiredParticipation': string;
|
||||||
|
'governance.proposal.updateMarket.maxClose': string;
|
||||||
|
'governance.proposal.updateMarket.maxEnact': string;
|
||||||
|
'governance.proposal.updateMarket.minClose': string;
|
||||||
|
'governance.proposal.updateMarket.minEnact': string;
|
||||||
|
'governance.proposal.updateMarket.minProposerBalance': string;
|
||||||
|
'governance.proposal.updateMarket.minProposerEquityLikeShare': string;
|
||||||
|
'governance.proposal.updateMarket.minVoterBalance': string;
|
||||||
|
'governance.proposal.updateMarket.requiredMajority': string;
|
||||||
|
'governance.proposal.updateMarket.requiredMajorityLP': string;
|
||||||
|
'governance.proposal.updateMarket.requiredParticipation': string;
|
||||||
|
'governance.proposal.updateMarket.requiredParticipationLP': string;
|
||||||
|
'governance.proposal.updateNetParam.maxClose': string;
|
||||||
|
'governance.proposal.updateNetParam.maxEnact': string;
|
||||||
|
'governance.proposal.updateNetParam.minClose': string;
|
||||||
|
'governance.proposal.updateNetParam.minEnact': string;
|
||||||
|
'governance.proposal.updateNetParam.minProposerBalance': string;
|
||||||
|
'governance.proposal.updateNetParam.minVoterBalance': string;
|
||||||
|
'governance.proposal.updateNetParam.requiredMajority': string;
|
||||||
|
'governance.proposal.updateNetParam.requiredParticipation': string;
|
||||||
|
'limits.assets.proposeEnabledFrom': string;
|
||||||
|
'limits.markets.maxPeggedOrders': string;
|
||||||
|
'limits.markets.proposeEnabledFrom': string;
|
||||||
|
'market.auction.maximumDuration': string;
|
||||||
|
'market.auction.minimumDuration': string;
|
||||||
|
'market.fee.factors.infrastructureFee': string;
|
||||||
|
'market.fee.factors.makerFee': string;
|
||||||
|
'market.liquidity.bondPenaltyParameter': string;
|
||||||
|
'market.liquidity.maximumLiquidityFeeFactorLevel': string;
|
||||||
|
'market.liquidity.minimum.probabilityOfTrading.lpOrders': string;
|
||||||
|
'market.liquidity.probabilityOfTrading.tau.scaling': string;
|
||||||
|
'market.liquidity.providers.fee.distributionTimeStep': string;
|
||||||
|
'market.liquidity.stakeToCcyVolume': string;
|
||||||
|
'market.liquidity.targetstake.triggering.ratio': string;
|
||||||
|
'market.liquidityProvision.minLpStakeQuantumMultiple': string;
|
||||||
|
'market.liquidityProvision.shapes.maxSize': string;
|
||||||
|
'market.margin.scalingFactors': string;
|
||||||
|
'market.monitor.price.defaultParameters': string;
|
||||||
|
'market.stake.target.scalingFactor': string;
|
||||||
|
'market.stake.target.timeWindow': string;
|
||||||
|
'market.value.windowLength': string;
|
||||||
|
'network.checkpoint.timeElapsedBetweenCheckpoints': string;
|
||||||
|
'network.floatingPointUpdates.delay': string;
|
||||||
|
'network.markPriceUpdateMaximumFrequency': string;
|
||||||
|
'network.transaction.defaultgas': string;
|
||||||
|
'network.transactions.maxgasperblock': string;
|
||||||
|
'network.transactions.minBlockCapacity': string;
|
||||||
|
'network.validators.ersatz.multipleOfTendermintValidators': string;
|
||||||
|
'network.validators.ersatz.rewardFactor': string;
|
||||||
|
'network.validators.incumbentBonus': string;
|
||||||
|
'network.validators.minimumEthereumEventsForNewValidator': string;
|
||||||
|
'network.validators.multisig.numberOfSigners': string;
|
||||||
|
'network.validators.tendermint.number': string;
|
||||||
|
'reward.asset': string;
|
||||||
|
'reward.staking.delegation.competitionLevel': string;
|
||||||
|
'reward.staking.delegation.delegatorShare': string;
|
||||||
|
'reward.staking.delegation.maxPayoutPerEpoch': string;
|
||||||
|
'reward.staking.delegation.maxPayoutPerParticipant': string;
|
||||||
|
'reward.staking.delegation.minValidators': string;
|
||||||
|
'reward.staking.delegation.minimumValidatorStake': string;
|
||||||
|
'reward.staking.delegation.optimalStakeMultiplier': string;
|
||||||
|
'reward.staking.delegation.payoutDelay': string;
|
||||||
|
'reward.staking.delegation.payoutFraction': string;
|
||||||
|
'rewards.marketCreationQuantumMultiple': string;
|
||||||
|
'snapshot.interval.length': string;
|
||||||
|
'spam.pow.difficulty': string;
|
||||||
|
'spam.pow.hashFunction': string;
|
||||||
|
'spam.pow.increaseDifficulty': string;
|
||||||
|
'spam.pow.numberOfPastBlocks': string;
|
||||||
|
'spam.pow.numberOfTxPerBlock': string;
|
||||||
|
'spam.protection.delegation.min.tokens': string;
|
||||||
|
'spam.protection.max.batchSize': string;
|
||||||
|
'spam.protection.max.delegations': string;
|
||||||
|
'spam.protection.max.proposals': string;
|
||||||
|
'spam.protection.max.votes': string;
|
||||||
|
'spam.protection.maxUserTransfersPerEpoch': string;
|
||||||
|
'spam.protection.minMultisigUpdates': string;
|
||||||
|
'spam.protection.minimumWithdrawalQuantumMultiple': string;
|
||||||
|
'spam.protection.proposal.min.tokens': string;
|
||||||
|
'spam.protection.voting.min.tokens': string;
|
||||||
|
'transfer.fee.factor': string;
|
||||||
|
'transfer.minTransferQuantumMultiple': string;
|
||||||
|
'validator.performance.scaling.factor': string;
|
||||||
|
'validators.delegation.minAmount': string;
|
||||||
|
'validators.epoch.length': string;
|
||||||
|
'validators.vote.required': string;
|
||||||
|
}
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
const epochTimeout = Cypress.env('epochTimeout');
|
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'convert_token_value_to_number',
|
|
||||||
{ prevSubject: true },
|
|
||||||
(subject) => {
|
|
||||||
return parseFloat(subject.replace(/,/g, ''));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const navigation = {
|
|
||||||
section: '[data-testid="navigation"]',
|
|
||||||
vesting: '[href="/token/redeem"]',
|
|
||||||
validators: '[href="/validators"]',
|
|
||||||
rewards: '[href="/rewards"]',
|
|
||||||
withdraw: '[href="/token/withdraw"]',
|
|
||||||
proposals: '[href="/proposals"]',
|
|
||||||
pageSpinner: '[data-testid="splash-loader"]',
|
|
||||||
supply: '[href="/token/tranches"]',
|
|
||||||
token: '[href="/token"]',
|
|
||||||
};
|
|
||||||
|
|
||||||
const topLevelRoutes = ['proposals', 'validators', 'rewards'];
|
|
||||||
const tokenDropDown = 'state-trigger';
|
|
||||||
|
|
||||||
Cypress.Commands.add('navigate_to', (page) => {
|
|
||||||
if (!topLevelRoutes.includes(page)) {
|
|
||||||
// FIXME: Timeout madness
|
|
||||||
cy.getByTestId(tokenDropDown, { timeout: 60000 }).eq(0).click();
|
|
||||||
cy.get('[data-testid="token-dropdown"]:visible').within(() => {
|
|
||||||
cy.get(navigation[page]).eq(0).click();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
|
||||||
cy.get(navigation[page]).eq(0).click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('verify_tab_highlighted', (page) => {
|
|
||||||
return cy.get(navigation.section).within(() => {
|
|
||||||
if (!topLevelRoutes.includes(page)) {
|
|
||||||
cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click();
|
|
||||||
cy.get('[data-testid="token-dropdown"]:visible').within(() => {
|
|
||||||
cy.get(navigation[page]).should('have.attr', 'aria-current');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cy.get(navigation[page]).should('have.attr', 'aria-current');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('verify_page_header', (text) => {
|
|
||||||
return cy.get('header h1').should('be.visible').and('have.text', text);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('wait_for_spinner', () => {
|
|
||||||
cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist');
|
|
||||||
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is a workaround function to begin tests with associating tokens without failing
|
|
||||||
// Should be removed when eth transaction bug is fixed
|
|
||||||
export function associateTokenStartOfTests() {
|
|
||||||
cy.highlight(`Associating tokens for first time`);
|
|
||||||
cy.ethereum_wallet_connect();
|
|
||||||
cy.connectVegaWallet();
|
|
||||||
cy.get('[href="/token/associate"]:visible').first().click();
|
|
||||||
cy.getByTestId('associate-radio-wallet', { timeout: 30000 }).click();
|
|
||||||
cy.getByTestId('token-amount-input', epochTimeout).type('1');
|
|
||||||
cy.getByTestId('token-input-submit-button', txTimeout)
|
|
||||||
.should('be.enabled')
|
|
||||||
.click();
|
|
||||||
cy.contains(
|
|
||||||
`Associating with Vega key. Waiting for ${Cypress.env(
|
|
||||||
'blockConfirmations'
|
|
||||||
)} more confirmations..`,
|
|
||||||
txTimeout
|
|
||||||
).should('be.visible');
|
|
||||||
cy.getByTestId('associated-amount', txTimeout).should('contain.text', '1');
|
|
||||||
// Wait is needed to allow time for transaction to complete
|
|
||||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
||||||
cy.wait(10000);
|
|
||||||
cy.vega_wallet_teardown();
|
|
||||||
cy.clearLocalStorage();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
const tokenDropDown = 'state-trigger';
|
||||||
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
|
|
||||||
|
export enum navigation {
|
||||||
|
section = 'nav',
|
||||||
|
vesting = '[href="/token/redeem"]',
|
||||||
|
validators = '[href="/validators"]',
|
||||||
|
rewards = '[href="/rewards"]',
|
||||||
|
withdraw = '[href="/token/withdraw"]',
|
||||||
|
proposals = '[href="/proposals"]',
|
||||||
|
pageSpinner = '[data-testid="splash-loader"]',
|
||||||
|
supply = '[href="/token/tranches"]',
|
||||||
|
token = '[href="/token"]',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertTokenValueToNumber(subject: string) {
|
||||||
|
return cy.wrap(parseFloat(subject.replace(/,/g, '')));
|
||||||
|
}
|
||||||
|
|
||||||
|
const topLevelRoutes = [
|
||||||
|
navigation.proposals,
|
||||||
|
navigation.validators,
|
||||||
|
navigation.rewards,
|
||||||
|
];
|
||||||
|
|
||||||
|
export function navigateTo(page: navigation) {
|
||||||
|
if (!topLevelRoutes.includes(page)) {
|
||||||
|
cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click();
|
||||||
|
cy.getByTestId('token-dropdown').within(() => {
|
||||||
|
cy.get(page).eq(0).click();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return cy.get(navigation.section, { timeout: 10000 }).within(() => {
|
||||||
|
cy.get(page).eq(0).click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyTabHighlighted(page: navigation) {
|
||||||
|
return cy.get(navigation.section).within(() => {
|
||||||
|
if (!topLevelRoutes.includes(page)) {
|
||||||
|
cy.getByTestId(tokenDropDown, { timeout: 10000 }).eq(0).click();
|
||||||
|
cy.get('[data-testid="token-dropdown"]:visible').within(() => {
|
||||||
|
cy.get(page).should('have.attr', 'aria-current');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cy.get(page).should('have.attr', 'aria-current');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyPageHeader(text: string) {
|
||||||
|
return cy.get('header h1').should('be.visible').and('have.text', text);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitForSpinner() {
|
||||||
|
cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist');
|
||||||
|
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyUnstakedBalance(amount: number) {
|
||||||
|
cy.getByTestId('vega-wallet-balance-unstaked', txTimeout).should(
|
||||||
|
'contain',
|
||||||
|
amount,
|
||||||
|
txTimeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyStakedBalance(amount: number) {
|
||||||
|
cy.getByTestId('vega-wallet-balance-staked-validators', txTimeout)
|
||||||
|
.should('contain', amount, txTimeout)
|
||||||
|
.and('contain', '…');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyEthWalletTotalAssociatedBalance(amount: string) {
|
||||||
|
cy.getByTestId('currency-locked', txTimeout)
|
||||||
|
.should('contain', amount)
|
||||||
|
.and('be.visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyEthWalletAssociatedBalance(amount: string) {
|
||||||
|
cy.getByTestId('eth-wallet-associated-balances', txTimeout)
|
||||||
|
.contains(Cypress.env('vegaWalletPublicKeyShort'), txTimeout)
|
||||||
|
.parent(txTimeout)
|
||||||
|
.should('contain', amount, txTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeDialog() {
|
||||||
|
cy.getByTestId('dialog-close').click();
|
||||||
|
}
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
const newProposalButton = '[data-testid="new-proposal-link"]';
|
|
||||||
const proposalInformationTableRows = '[data-testid="key-value-table-row"]';
|
|
||||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
|
||||||
const newProposalTitle = '[data-testid="proposal-title"]';
|
|
||||||
const newProposalDescription = '[data-testid="proposal-description"]';
|
|
||||||
const proposalDetails = '[data-testid="proposal-details"]';
|
|
||||||
const rawProposalData = '[data-testid="proposal-data"]';
|
|
||||||
const voteButtons = '[data-testid="vote-buttons"]';
|
|
||||||
const dialogTitle = '[data-testid="dialog-title"]';
|
|
||||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
|
||||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
|
||||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
|
||||||
const epochTimeout = Cypress.env('epochTimeout');
|
|
||||||
const proposalTimeout = { timeout: 14000 };
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'convert_unix_timestamp_to_governance_data_table_date_format',
|
|
||||||
(unixTimestamp, monthTextLength = 'longMonth') => {
|
|
||||||
let dateSupplied = new Date(unixTimestamp * 1000),
|
|
||||||
year = dateSupplied.getFullYear(),
|
|
||||||
months = [
|
|
||||||
'January',
|
|
||||||
'February',
|
|
||||||
'March',
|
|
||||||
'April',
|
|
||||||
'May',
|
|
||||||
'June',
|
|
||||||
'July',
|
|
||||||
'August',
|
|
||||||
'September',
|
|
||||||
'October',
|
|
||||||
'November',
|
|
||||||
'December',
|
|
||||||
],
|
|
||||||
month = months[dateSupplied.getMonth()],
|
|
||||||
shortMonth = months[dateSupplied.getMonth()].substring(0, 3),
|
|
||||||
date = dateSupplied.getDate();
|
|
||||||
|
|
||||||
if (monthTextLength === 'longMonth') return `${date} ${month} ${year}`;
|
|
||||||
else return `${date} ${shortMonth} ${year}`;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'create_ten_digit_unix_timestamp_for_specified_days',
|
|
||||||
(durationDays) => {
|
|
||||||
let today = new Date();
|
|
||||||
let timestamp = today.setDate(today.getDate() + parseInt(durationDays));
|
|
||||||
timestamp = Math.floor(timestamp / 1000);
|
|
||||||
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add('enter_raw_proposal_body', (timestamp) => {
|
|
||||||
cy.fixture('/proposals/raw.json').then((rawProposal) => {
|
|
||||||
rawProposal.terms.closingTimestamp = timestamp;
|
|
||||||
rawProposal.rationale.title += timestamp;
|
|
||||||
let proposalPayload = JSON.stringify(rawProposal);
|
|
||||||
|
|
||||||
cy.get(rawProposalData).type(proposalPayload, {
|
|
||||||
parseSpecialCharSequences: false,
|
|
||||||
delay: 2,
|
|
||||||
});
|
|
||||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
|
||||||
cy.wrap(rawProposal);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'enter_unique_freeform_proposal_body',
|
|
||||||
(timestamp, proposalTitle) => {
|
|
||||||
cy.get(newProposalTitle).type(proposalTitle);
|
|
||||||
cy.get(newProposalDescription).type(
|
|
||||||
'this is a e2e freeform proposal description'
|
|
||||||
);
|
|
||||||
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
|
|
||||||
cy.getByTestId('proposal-submit').should('be.visible').click();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'get_submitted_proposal_from_proposal_list',
|
|
||||||
(proposalTitle) => {
|
|
||||||
cy.get_proposal_id_from_list(proposalTitle).then(() => {
|
|
||||||
cy.get('@proposalIdText').then((proposalId) => {
|
|
||||||
return cy.get(`#${proposalId}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add('get_proposal_id_from_list', (proposalTitle) => {
|
|
||||||
cy.contains(proposalTitle)
|
|
||||||
.parentsUntil(proposalListItem)
|
|
||||||
.within(() => {
|
|
||||||
cy.get(proposalDetails)
|
|
||||||
.invoke('text')
|
|
||||||
.then((proposalIdText) => {
|
|
||||||
let newProposalId;
|
|
||||||
if (proposalIdText.includes('Freeform proposal')) {
|
|
||||||
newProposalId = proposalIdText.replace('Freeform proposal: ', '');
|
|
||||||
}
|
|
||||||
cy.wrap(newProposalId).as('proposalIdText');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'get_governance_proposal_date_format_for_specified_days',
|
|
||||||
(days, shortOrLong) => {
|
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days(days).then((date) => {
|
|
||||||
cy.convert_unix_timestamp_to_governance_data_table_date_format(
|
|
||||||
date,
|
|
||||||
shortOrLong
|
|
||||||
).then((convertedDate) => {
|
|
||||||
return convertedDate;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add('get_proposal_information_from_table', (heading) => {
|
|
||||||
cy.get(proposalInformationTableRows).contains(heading).siblings();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('vote_for_proposal', (vote) => {
|
|
||||||
cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 });
|
|
||||||
cy.get(voteButtons).contains(vote).click();
|
|
||||||
cy.get(dialogTitle).should('have.text', 'Transaction complete');
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('wait_for_proposal_sync', () => {
|
|
||||||
// This is a workaround function required because after posting a proposal
|
|
||||||
// and waiting for the ProposalEvent network call to respond there can still be a few seconds
|
|
||||||
// before proposal appears in the list - so rather than hard coded wait - we just wait on the
|
|
||||||
// delegation checks that are performed on the governance page.
|
|
||||||
|
|
||||||
cy.intercept('POST', '/query', (req) => {
|
|
||||||
if (req.body.operationName === 'Delegations') {
|
|
||||||
req.alias = 'proposalDelegationsCompletion';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// waiting for two network calls
|
|
||||||
cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']);
|
|
||||||
|
|
||||||
// Turn off this intercept from here on in
|
|
||||||
cy.intercept('POST', '/query', (req) => {
|
|
||||||
if (req.body.operationName === 'Delegations') {
|
|
||||||
req.continue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('navigate_to_page_if_not_already_loaded', (section) => {
|
|
||||||
cy.url().then((url) => {
|
|
||||||
if (url != `http://localhost:4210/${section}`) {
|
|
||||||
cy.navigate_to(section);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('get_sort_order_of_supplied_array', (suppliedArray) => {
|
|
||||||
const tempArray = [];
|
|
||||||
for (let index = 1; index < suppliedArray.length; index++) {
|
|
||||||
tempArray.push(
|
|
||||||
suppliedArray[index - 1].localeCompare(suppliedArray[index])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (tempArray.every((n) => n <= 0)) return 'ascending';
|
|
||||||
else if (tempArray.every((n) => n >= 0)) return 'descending';
|
|
||||||
else return 'unsorted';
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('go_to_make_new_proposal', (proposalType) => {
|
|
||||||
cy.navigate_to_page_if_not_already_loaded('proposals');
|
|
||||||
cy.get(newProposalButton).should('be.visible').click();
|
|
||||||
cy.url().should('include', '/proposals/propose');
|
|
||||||
cy.get('li').should('contain.text', proposalType).and('be.visible');
|
|
||||||
cy.get('li').contains(proposalType).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('wait_for_proposal_submitted', () => {
|
|
||||||
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
|
||||||
'be.visible'
|
|
||||||
);
|
|
||||||
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
|
|
||||||
cy.get(dialogCloseButton).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
export function createRawProposal(proposerBalance) {
|
|
||||||
if (proposerBalance)
|
|
||||||
cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance);
|
|
||||||
cy.go_to_make_new_proposal('raw proposal');
|
|
||||||
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
|
|
||||||
(closingDateTimestamp) => {
|
|
||||||
cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
cy.wait_for_proposal_submitted();
|
|
||||||
cy.wait_for_proposal_sync();
|
|
||||||
cy.navigate_to('proposals');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateFreeFormProposalTitle() {
|
|
||||||
const randomNum = Math.floor(Math.random() * 1000) + 1;
|
|
||||||
return randomNum + ': Freeform e2e proposal';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createFreeformProposal(proposalTitle) {
|
|
||||||
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
|
|
||||||
cy.enter_unique_freeform_proposal_body('50', proposalTitle);
|
|
||||||
cy.wait_for_proposal_submitted();
|
|
||||||
cy.wait_for_proposal_sync();
|
|
||||||
cy.getByTestId('proposal-title').invoke('text').as('proposalTitle');
|
|
||||||
cy.navigate_to('proposals');
|
|
||||||
}
|
|
||||||
|
|
||||||
export const governanceProposalType = {
|
|
||||||
NETWORK_PARAMETER: 'Network parameter',
|
|
||||||
NEW_MARKET: 'New market',
|
|
||||||
UPDATE_MARKET: 'Update market',
|
|
||||||
NEW_ASSET: 'New asset',
|
|
||||||
FREEFORM: 'Freeform',
|
|
||||||
RAW: 'raw proposal',
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
import { closeDialog, navigateTo, navigation } from './common.functions';
|
||||||
|
import { ensureSpecifiedUnstakedTokensAreAssociated } from './staking.functions';
|
||||||
|
|
||||||
|
const newProposalButton = '[data-testid="new-proposal-link"]';
|
||||||
|
const proposalInformationTableRows = '[data-testid="key-value-table-row"]';
|
||||||
|
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||||
|
const newProposalTitle = '[data-testid="proposal-title"]';
|
||||||
|
const newProposalDescription = '[data-testid="proposal-description"]';
|
||||||
|
const proposalDetails = '[data-testid="proposal-details"]';
|
||||||
|
const rawProposalData = '[data-testid="proposal-data"]';
|
||||||
|
const voteButtons = '[data-testid="vote-buttons"]';
|
||||||
|
const dialogTitle = '[data-testid="dialog-title"]';
|
||||||
|
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||||
|
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||||
|
const epochTimeout = Cypress.env('epochTimeout');
|
||||||
|
const proposalTimeout = { timeout: 14000 };
|
||||||
|
|
||||||
|
export function convertUnixTimestampToDateformat(
|
||||||
|
unixTimestamp: number,
|
||||||
|
monthTextLength = 'longMonth'
|
||||||
|
) {
|
||||||
|
const dateSupplied = new Date(unixTimestamp * 1000);
|
||||||
|
const year = dateSupplied.getFullYear();
|
||||||
|
const months = [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December',
|
||||||
|
];
|
||||||
|
const month = months[dateSupplied.getMonth()];
|
||||||
|
const shortMonth = months[dateSupplied.getMonth()].substring(0, 3),
|
||||||
|
date = dateSupplied.getDate();
|
||||||
|
|
||||||
|
if (monthTextLength === 'longMonth') {
|
||||||
|
return cy.wrap(`${date} ${month} ${year}`);
|
||||||
|
} else return cy.wrap(`${date} ${shortMonth} ${year}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTenDigitUnixTimeStampForSpecifiedDays(
|
||||||
|
durationDays: number
|
||||||
|
) {
|
||||||
|
const today = new Date();
|
||||||
|
let timestamp = today.setDate(today.getDate() + durationDays);
|
||||||
|
return (timestamp = Math.floor(timestamp / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enterRawProposalBody(timestamp: number) {
|
||||||
|
cy.fixture('/proposals/raw.json').then((rawProposal) => {
|
||||||
|
rawProposal.terms.closingTimestamp = timestamp;
|
||||||
|
rawProposal.rationale.title += timestamp;
|
||||||
|
const proposalPayload = JSON.stringify(rawProposal);
|
||||||
|
|
||||||
|
cy.get(rawProposalData).type(proposalPayload, {
|
||||||
|
parseSpecialCharSequences: false,
|
||||||
|
delay: 2,
|
||||||
|
});
|
||||||
|
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||||
|
cy.wrap(rawProposal).as('rawProposal');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enterUniqueFreeFormProposalBody(
|
||||||
|
timestamp: string,
|
||||||
|
proposalTitle: string
|
||||||
|
) {
|
||||||
|
cy.get(newProposalTitle).type(proposalTitle);
|
||||||
|
cy.get(newProposalDescription).type(
|
||||||
|
'this is a e2e freeform proposal description'
|
||||||
|
);
|
||||||
|
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
|
||||||
|
cy.getByTestId('proposal-submit').should('be.visible').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSubmittedProposalFromProposalList(proposalTitle: string) {
|
||||||
|
getProposalIdFromList(proposalTitle);
|
||||||
|
cy.get('@proposalIdText').then((proposalId) => {
|
||||||
|
cy.get(`#${proposalId}`).as('submittedProposal');
|
||||||
|
});
|
||||||
|
return cy.get('@submittedProposal');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProposalIdFromList(proposalTitle: string) {
|
||||||
|
cy.contains(proposalTitle)
|
||||||
|
.parentsUntil(proposalListItem)
|
||||||
|
.within(() => {
|
||||||
|
cy.get(proposalDetails)
|
||||||
|
.invoke('text')
|
||||||
|
.then((proposalIdText) => {
|
||||||
|
let newProposalId;
|
||||||
|
if (proposalIdText.includes('Freeform proposal')) {
|
||||||
|
newProposalId = proposalIdText.replace('Freeform proposal: ', '');
|
||||||
|
}
|
||||||
|
cy.wrap(newProposalId).as('proposalIdText');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getGovernanceProposalDateFormatForSpecifiedDays(
|
||||||
|
days: number,
|
||||||
|
shortOrLong?: string
|
||||||
|
) {
|
||||||
|
return convertUnixTimestampToDateformat(
|
||||||
|
createTenDigitUnixTimeStampForSpecifiedDays(days),
|
||||||
|
shortOrLong
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProposalInformationFromTable(heading: string) {
|
||||||
|
return cy.get(proposalInformationTableRows).contains(heading).siblings();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function voteForProposal(vote: string) {
|
||||||
|
cy.contains('Vote breakdown').should('be.visible', { timeout: 10000 });
|
||||||
|
cy.get(voteButtons).contains(vote).click();
|
||||||
|
cy.get(dialogTitle, proposalTimeout).should(
|
||||||
|
'have.text',
|
||||||
|
'Transaction complete'
|
||||||
|
);
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitForProposalSync() {
|
||||||
|
// This is a workaround function required because after posting a proposal
|
||||||
|
// and waiting for the ProposalEvent network call to respond there can still be a few seconds
|
||||||
|
// before proposal appears in the list - so rather than hard coded wait - we just wait on the
|
||||||
|
// delegation checks that are performed on the governance page.
|
||||||
|
|
||||||
|
cy.intercept('POST', '/query', (req) => {
|
||||||
|
if (req.body.operationName === 'Delegations') {
|
||||||
|
req.alias = 'proposalDelegationsCompletion';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// waiting for two network calls
|
||||||
|
cy.wait(['@proposalDelegationsCompletion', '@proposalDelegationsCompletion']);
|
||||||
|
|
||||||
|
// Turn off this intercept from here on in
|
||||||
|
cy.intercept('POST', '/query', (req) => {
|
||||||
|
if (req.body.operationName === 'Delegations') {
|
||||||
|
req.continue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSortOrderOfSuppliedArray(suppliedArray: string[]) {
|
||||||
|
const tempArray = [];
|
||||||
|
for (let index = 1; index < suppliedArray.length; index++) {
|
||||||
|
tempArray.push(
|
||||||
|
suppliedArray[index - 1].localeCompare(suppliedArray[index])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (tempArray.every((n) => n <= 0)) return 'ascending';
|
||||||
|
else if (tempArray.every((n) => n >= 0)) return 'descending';
|
||||||
|
else return 'unsorted';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goToMakeNewProposal(proposalType: string) {
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
cy.get(newProposalButton).should('be.visible').click();
|
||||||
|
cy.url().should('include', '/proposals/propose');
|
||||||
|
cy.get('li').should('contain.text', proposalType).and('be.visible');
|
||||||
|
cy.get('li').contains(proposalType).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitForProposalSubmitted() {
|
||||||
|
cy.contains('Awaiting network confirmation', epochTimeout).should(
|
||||||
|
'be.visible'
|
||||||
|
);
|
||||||
|
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRawProposal(proposerBalance?: string) {
|
||||||
|
if (proposerBalance) {
|
||||||
|
ensureSpecifiedUnstakedTokensAreAssociated(proposerBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
goToMakeNewProposal(governanceProposalType.RAW);
|
||||||
|
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
|
||||||
|
waitForProposalSubmitted();
|
||||||
|
waitForProposalSync();
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateFreeFormProposalTitle() {
|
||||||
|
const randomNum = Math.floor(Math.random() * 1000) + 1;
|
||||||
|
return randomNum + ': Freeform e2e proposal';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFreeformProposal(proposalTitle: string) {
|
||||||
|
goToMakeNewProposal(governanceProposalType.FREEFORM);
|
||||||
|
enterUniqueFreeFormProposalBody('50', proposalTitle);
|
||||||
|
waitForProposalSubmitted();
|
||||||
|
waitForProposalSync();
|
||||||
|
cy.getByTestId('proposal-title').invoke('text').as('proposalTitle');
|
||||||
|
navigateTo(navigation.proposals);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const governanceProposalType = {
|
||||||
|
NETWORK_PARAMETER: 'Network parameter',
|
||||||
|
NEW_MARKET: 'New market',
|
||||||
|
UPDATE_MARKET: 'Update market',
|
||||||
|
NEW_ASSET: 'New asset',
|
||||||
|
FREEFORM: 'Freeform',
|
||||||
|
RAW: 'raw proposal',
|
||||||
|
};
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
declare namespace Cypress {
|
||||||
|
// specify additional properties in the TestConfig object
|
||||||
|
// in our case we will add "tags" property
|
||||||
|
interface SuiteConfigOverrides {
|
||||||
|
/**
|
||||||
|
* List of tags for this test
|
||||||
|
* @example a single tag
|
||||||
|
* it('logs in', { tags: '@smoke' }, () => { ... })
|
||||||
|
* @example multiple tags
|
||||||
|
* it('works', { tags: ['@smoke', '@slow'] }, () => { ... })
|
||||||
|
*/
|
||||||
|
tags?: string | string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Cypress {
|
||||||
|
grep?: (grep?: string, tags?: string, burn?: string) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import '@vegaprotocol/cypress';
|
import '@vegaprotocol/cypress';
|
||||||
import 'cypress-real-events/support';
|
import 'cypress-real-events/support';
|
||||||
|
|
||||||
import './common.functions.js';
|
import './common.functions.ts';
|
||||||
import './staking.functions.js';
|
import './staking.functions.ts';
|
||||||
import './governance.functions.js';
|
import './governance.functions.ts';
|
||||||
import './wallet-eth.functions.js';
|
import './wallet-eth.functions.ts';
|
||||||
import './wallet-teardown.functions.js';
|
import './wallet-teardown.functions.ts';
|
||||||
import './wallet-vega.functions.js';
|
import './wallet-vega.functions.ts';
|
||||||
import './proposal.functions.ts';
|
import './proposal.functions.ts';
|
||||||
import registerCypressGrep from '@cypress/grep';
|
import registerCypressGrep from '@cypress/grep';
|
||||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||||
|
|||||||
+125
-114
@@ -1,3 +1,6 @@
|
|||||||
|
import { closeDialog } from './common.functions';
|
||||||
|
import { vegaWalletTeardown } from './wallet-teardown.functions';
|
||||||
|
|
||||||
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
|
||||||
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
|
||||||
const tokenInputApprove = '[data-testid="token-input-approve-button"]';
|
const tokenInputApprove = '[data-testid="token-input-approve-button"]';
|
||||||
@@ -12,53 +15,55 @@ const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
|
|||||||
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
|
const associateContractRadioButton = '[data-testid="associate-radio-contract"]';
|
||||||
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
const stakeMaximumTokens = '[data-testid="token-amount-use-maximum"]';
|
||||||
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
const stakeValidatorListPendingStake = '[col-id="pendingStake"]';
|
||||||
const stakeValidatorListTotalStake = '[col-id="stake"] > div > span';
|
const stakeValidatorListTotalStake = 'total-stake';
|
||||||
const stakeValidatorListTotalShare = '[col-id="stakeShare"] > div > span';
|
const stakeValidatorListTotalShare = 'total-stake-share';
|
||||||
const stakeValidatorListName = '[col-id="validator"]';
|
const stakeValidatorListName = '[col-id="validator"]';
|
||||||
const vegaKeySelector = '#vega-key-selector';
|
const vegaKeySelector = '#vega-key-selector';
|
||||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
|
||||||
|
|
||||||
const txTimeout = Cypress.env('txTimeout');
|
const txTimeout = Cypress.env('txTimeout');
|
||||||
const epochTimeout = Cypress.env('epochTimeout');
|
const epochTimeout = Cypress.env('epochTimeout');
|
||||||
|
|
||||||
Cypress.Commands.add('wait_for_beginning_of_epoch', () => {
|
export function waitForBeginningOfEpoch() {
|
||||||
cy.contains('Waiting for next epoch to start', epochTimeout).should(
|
cy.contains('Waiting for next epoch to start', epochTimeout).should(
|
||||||
'not.exist'
|
'not.exist'
|
||||||
);
|
);
|
||||||
cy.contains('Waiting for next epoch to start', epochTimeout).should(
|
cy.contains('Waiting for next epoch to start', epochTimeout).should(
|
||||||
'be.visible'
|
'be.visible'
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('staking_validator_page_add_stake', (stake) => {
|
export function stakingValidatorPageAddStake(stake: string) {
|
||||||
cy.highlight(`Adding a stake of ${stake}`);
|
cy.highlight(`Adding a stake of ${stake}`);
|
||||||
cy.get(addStakeRadioButton, epochTimeout).click({ force: true });
|
cy.get(addStakeRadioButton, epochTimeout).click({ force: true });
|
||||||
cy.get(tokenAmountInputBox).type(stake);
|
cy.get(tokenAmountInputBox).type(stake);
|
||||||
cy.wait_for_beginning_of_epoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.get(tokenSubmitButton, epochTimeout)
|
cy.get(tokenSubmitButton, epochTimeout)
|
||||||
.should('be.enabled')
|
.should('be.enabled')
|
||||||
.and('contain', `Add ${stake} $VEGA tokens`)
|
.and('contain', `Add ${stake} $VEGA tokens`)
|
||||||
.and('be.visible')
|
.and('be.visible')
|
||||||
.click();
|
.click();
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => {
|
export function stakingValidatorPageRemoveStake(stake: string) {
|
||||||
cy.highlight(`Removing a stake of ${stake}`);
|
cy.highlight(`Removing a stake of ${stake}`);
|
||||||
cy.get(removeStakeRadioButton, epochTimeout).click();
|
cy.get(removeStakeRadioButton, epochTimeout).click();
|
||||||
cy.get(tokenAmountInputBox).type(stake);
|
cy.get(tokenAmountInputBox).type(stake);
|
||||||
cy.wait_for_beginning_of_epoch();
|
waitForBeginningOfEpoch();
|
||||||
cy.get(tokenSubmitButton)
|
cy.get(tokenSubmitButton)
|
||||||
.should('be.enabled', epochTimeout)
|
.should('be.enabled', epochTimeout)
|
||||||
.and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`)
|
.and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`)
|
||||||
.and('be.visible')
|
.and('be.visible')
|
||||||
.click();
|
.click();
|
||||||
cy.get(dialogCloseButton).click();
|
closeDialog();
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => {
|
export function stakingPageAssociateTokens(
|
||||||
let approve = options && options.approve ? options.approve : false;
|
amount: string,
|
||||||
let type = options && options.type ? options.type : 'wallet';
|
options?: associateOptions
|
||||||
let skipConfirmation =
|
) {
|
||||||
|
const approve = options && options.approve ? options.approve : false;
|
||||||
|
const type = options && options.type ? options.type : 'wallet';
|
||||||
|
const skipConfirmation =
|
||||||
options && options.skipConfirmation ? options.skipConfirmation : false;
|
options && options.skipConfirmation ? options.skipConfirmation : false;
|
||||||
|
|
||||||
cy.highlight(`Associating ${amount} tokens from ${type}`);
|
cy.highlight(`Associating ${amount} tokens from ${type}`);
|
||||||
@@ -94,10 +99,13 @@ Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => {
|
|||||||
txTimeout
|
txTimeout
|
||||||
).should('be.visible');
|
).should('be.visible');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => {
|
export function stakingPageDisassociateTokens(
|
||||||
let type = options && options.type ? options.type : 'wallet';
|
amount: string,
|
||||||
|
options?: associateOptions
|
||||||
|
) {
|
||||||
|
const type = options && options.type ? options.type : 'wallet';
|
||||||
cy.highlight(
|
cy.highlight(
|
||||||
`Disassociating ${amount} tokens via Staking Page back to ${type}`
|
`Disassociating ${amount} tokens via Staking Page back to ${type}`
|
||||||
);
|
);
|
||||||
@@ -127,92 +135,89 @@ Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => {
|
|||||||
txTimeout
|
txTimeout
|
||||||
).should('be.visible');
|
).should('be.visible');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add(
|
export function stakingPageDisassociateAllTokens(type = 'wallet') {
|
||||||
'staking_page_disassociate_all_tokens',
|
cy.highlight(`Disassociating all tokens via Staking Page`);
|
||||||
(type = 'wallet') => {
|
cy.get(ethWalletDissociateButton).first().click();
|
||||||
cy.highlight(`Disassociating all tokens via Staking Page`);
|
cy.get(stakeMaximumTokens, epochTimeout).click();
|
||||||
cy.get(ethWalletDissociateButton).first().click();
|
cy.get(tokenSubmitButton, epochTimeout).click();
|
||||||
cy.get(stakeMaximumTokens, epochTimeout).click();
|
if (type === 'wallet') {
|
||||||
cy.get(tokenSubmitButton, epochTimeout).click();
|
cy.contains(
|
||||||
if (type === 'wallet') {
|
`$VEGA tokens have been returned to Ethereum wallet`,
|
||||||
cy.contains(
|
txTimeout
|
||||||
`$VEGA tokens have been returned to Ethereum wallet`,
|
).should('be.visible');
|
||||||
txTimeout
|
} else if (type === 'contract') {
|
||||||
).should('be.visible');
|
cy.contains(
|
||||||
} else if (type === 'contract') {
|
`$VEGA tokens have been returned to Vesting contract`,
|
||||||
cy.contains(
|
txTimeout
|
||||||
`$VEGA tokens have been returned to Vesting contract`,
|
).should('be.visible');
|
||||||
txTimeout
|
|
||||||
).should('be.visible');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
Cypress.Commands.add(
|
export function clickOnValidatorFromList(
|
||||||
'click_on_validator_from_list',
|
validatorNumber: number,
|
||||||
(validatorNumber, validatorName = null) => {
|
validatorName = null
|
||||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
) {
|
||||||
cy.wait_for_beginning_of_epoch();
|
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||||
// below is to ensure validator list is shown
|
waitForBeginningOfEpoch();
|
||||||
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
|
// below is to ensure validator list is shown
|
||||||
cy.get(stakeValidatorListPendingStake, txTimeout).should(
|
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
|
||||||
'not.contain',
|
cy.get(stakeValidatorListPendingStake, txTimeout).should(
|
||||||
'2,000,000,000,000,000,000.00' // number due to bug #936
|
'not.contain',
|
||||||
|
'2,000,000,000,000,000,000.00' // number due to bug #936
|
||||||
|
);
|
||||||
|
if (validatorName) {
|
||||||
|
cy.contains(validatorName).click();
|
||||||
|
} else {
|
||||||
|
cy.get(`[row-id="${validatorNumber}"]`)
|
||||||
|
.should('be.visible')
|
||||||
|
.find(stakeValidatorListName)
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateValidatorListTotalStakeAndShare(
|
||||||
|
positionOnList: string,
|
||||||
|
expectedTotalStake: string,
|
||||||
|
expectedTotalShare: string
|
||||||
|
) {
|
||||||
|
cy.contains('Loading...', epochTimeout).should('not.exist');
|
||||||
|
waitForBeginningOfEpoch();
|
||||||
|
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
||||||
|
cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should(
|
||||||
|
'have.text',
|
||||||
|
expectedTotalStake
|
||||||
);
|
);
|
||||||
if (validatorName) {
|
cy.getByTestId(stakeValidatorListTotalShare, epochTimeout).should(
|
||||||
cy.contains(validatorName).click();
|
'have.text',
|
||||||
} else {
|
expectedTotalShare
|
||||||
cy.get(`[row-id="${validatorNumber}"]`)
|
);
|
||||||
.should('be.visible')
|
});
|
||||||
.find(stakeValidatorListName)
|
}
|
||||||
.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
export function ensureSpecifiedUnstakedTokensAreAssociated(
|
||||||
'validate_validator_list_total_stake_and_share',
|
tokenAmount: string
|
||||||
(positionOnList, expectedTotalStake, expectedTotalShare) => {
|
) {
|
||||||
cy.contains('Loading...', epochTimeout).should('not.exist');
|
cy.highlight(`Ensuring ${tokenAmount} token(s) associated`);
|
||||||
cy.wait_for_beginning_of_epoch();
|
cy.get(vegaWalletUnstakedBalance)
|
||||||
cy.get(`[row-id="${positionOnList}"]`).within(() => {
|
.children()
|
||||||
cy.get(stakeValidatorListTotalStake, epochTimeout).should(
|
.children()
|
||||||
'have.text',
|
.eq(1)
|
||||||
expectedTotalStake
|
.invoke('text')
|
||||||
);
|
.then((unstakedBalance) => {
|
||||||
cy.get(stakeValidatorListTotalShare, epochTimeout).should(
|
if (parseFloat(unstakedBalance) != parseFloat(tokenAmount)) {
|
||||||
'have.text',
|
vegaWalletTeardown();
|
||||||
expectedTotalShare
|
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
||||||
);
|
'0.00',
|
||||||
|
txTimeout
|
||||||
|
);
|
||||||
|
stakingPageAssociateTokens(tokenAmount);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
export function closeStakingDialog() {
|
||||||
'ensure_specified_unstaked_tokens_are_associated',
|
|
||||||
(tokenAmount) => {
|
|
||||||
cy.highlight(`Ensuring ${tokenAmount} token(s) associated`);
|
|
||||||
cy.get(vegaWalletUnstakedBalance)
|
|
||||||
.children()
|
|
||||||
.children()
|
|
||||||
.eq(1)
|
|
||||||
.invoke('text')
|
|
||||||
.then((unstakedBalance) => {
|
|
||||||
if (parseFloat(unstakedBalance) != parseFloat(tokenAmount)) {
|
|
||||||
cy.vega_wallet_teardown();
|
|
||||||
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
|
|
||||||
'0.00',
|
|
||||||
txTimeout
|
|
||||||
);
|
|
||||||
cy.staking_page_associate_tokens(tokenAmount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add('close_staking_dialog', () => {
|
|
||||||
cy.getByTestId('dialog-title').should(
|
cy.getByTestId('dialog-title').should(
|
||||||
'contain.text',
|
'contain.text',
|
||||||
'At the beginning of the next epoch'
|
'At the beginning of the next epoch'
|
||||||
@@ -220,20 +225,26 @@ Cypress.Commands.add('close_staking_dialog', () => {
|
|||||||
cy.getByTestId('dialog-content').within(() => {
|
cy.getByTestId('dialog-content').within(() => {
|
||||||
cy.get('a').should('have.text', 'Back to Staking').click();
|
cy.get('a').should('have.text', 'Back to Staking').click();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
Cypress.Commands.add(
|
export function validateWalletCurrency(
|
||||||
'validate_wallet_currency',
|
currencyTitle: string,
|
||||||
(currencyTitle, expectedAmount) => {
|
expectedAmount: string
|
||||||
cy.get("[data-testid='currency-title']")
|
) {
|
||||||
.contains(currencyTitle)
|
cy.get("[data-testid='currency-title']")
|
||||||
.parent()
|
.contains(currencyTitle)
|
||||||
.parent()
|
.parent()
|
||||||
.within(() => {
|
.parent()
|
||||||
cy.getByTestId('currency-value', txTimeout).should(
|
.within(() => {
|
||||||
'have.text',
|
cy.getByTestId('currency-value', txTimeout).should(
|
||||||
expectedAmount
|
'have.text',
|
||||||
);
|
expectedAmount
|
||||||
});
|
);
|
||||||
}
|
});
|
||||||
);
|
}
|
||||||
|
|
||||||
|
interface associateOptions {
|
||||||
|
approve?: boolean;
|
||||||
|
type?: string;
|
||||||
|
skipConfirmation?: boolean;
|
||||||
|
}
|
||||||
+2
-2
@@ -3,7 +3,7 @@ const connectToEthButton =
|
|||||||
'[data-testid="connect-to-eth-wallet-button"]:visible';
|
'[data-testid="connect-to-eth-wallet-button"]:visible';
|
||||||
const capsuleWalletConnectButton = '[data-testid="web3-connector-Unknown"]';
|
const capsuleWalletConnectButton = '[data-testid="web3-connector-Unknown"]';
|
||||||
|
|
||||||
Cypress.Commands.add('ethereum_wallet_connect', () => {
|
export function ethereumWalletConnect() {
|
||||||
cy.highlight('Connecting Eth Wallet');
|
cy.highlight('Connecting Eth Wallet');
|
||||||
cy.get(connectToEthButton).within(() => {
|
cy.get(connectToEthButton).within(() => {
|
||||||
cy.contains('Connect Ethereum wallet to associate $VEGA')
|
cy.contains('Connect Ethereum wallet to associate $VEGA')
|
||||||
@@ -20,4 +20,4 @@ Cypress.Commands.add('ethereum_wallet_connect', () => {
|
|||||||
// It needs a few seconds before becoming operational
|
// It needs a few seconds before becoming operational
|
||||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||||
cy.wait(4000);
|
cy.wait(4000);
|
||||||
});
|
}
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
import {
|
|
||||||
StakingBridge,
|
|
||||||
Token,
|
|
||||||
TokenVesting,
|
|
||||||
TokenFaucetable,
|
|
||||||
CollateralBridge,
|
|
||||||
} from '@vegaprotocol/smart-contracts';
|
|
||||||
import { ethers, Wallet } from 'ethers';
|
|
||||||
|
|
||||||
const vegaWalletContainer = 'aside [data-testid="vega-wallet"]';
|
|
||||||
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
|
|
||||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
|
||||||
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
|
||||||
const vegaTokenAddress = Cypress.env('vegaTokenAddress');
|
|
||||||
const ethWalletPubKey = Cypress.env('ethWalletPublicKey');
|
|
||||||
const ethStakingBridgeContractAddress = Cypress.env(
|
|
||||||
'ethStakingBridgeContractAddress'
|
|
||||||
);
|
|
||||||
const ethProviderUrl = Cypress.env('ethProviderUrl');
|
|
||||||
const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`;
|
|
||||||
const transactionTimeout = '90000';
|
|
||||||
const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54';
|
|
||||||
|
|
||||||
before('Vega wallet teardown prep', function () {
|
|
||||||
cy.wrap(new ethers.providers.JsonRpcProvider({ url: ethProviderUrl }), {
|
|
||||||
log: false,
|
|
||||||
}).as('provider');
|
|
||||||
|
|
||||||
cy.wrap(Wallet.fromMnemonic(vegaWalletMnemonic, getAccount(0)).privateKey, {
|
|
||||||
log: false,
|
|
||||||
}).then((privateKey) => {
|
|
||||||
cy.wrap(new Wallet(privateKey, this.provider), { log: false }).as('signer');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('@signer', { log: false }).then((signer) => {
|
|
||||||
cy.wrap(new StakingBridge(ethStakingBridgeContractAddress, signer), {
|
|
||||||
log: false,
|
|
||||||
}).as('stakingBridgeContract');
|
|
||||||
cy.wrap(new TokenVesting(vegaTokenContractAddress, signer), {
|
|
||||||
log: false,
|
|
||||||
}).as('vestingContract');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
cy.wrap(this.stakingBridgeContract).as('stakingBridgeContract');
|
|
||||||
cy.wrap(this.vestingContract).as('vestingContract');
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('deposit_asset', function (assetEthAddress, amount) {
|
|
||||||
cy.highlight('Depositing asset into vegawallet');
|
|
||||||
cy.get('@signer', { log: false }).then((signer) => {
|
|
||||||
// Approve asset
|
|
||||||
cy.wrap(
|
|
||||||
new TokenFaucetable(assetEthAddress, signer).approve(
|
|
||||||
Erc20BridgeAddress,
|
|
||||||
amount + '0'.repeat(19)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
cy.wrap(new CollateralBridge(Erc20BridgeAddress, signer), {
|
|
||||||
log: false,
|
|
||||||
}).then((bridge) => {
|
|
||||||
// Deposit asset into vega wallet
|
|
||||||
cy.wrap(
|
|
||||||
bridge.deposit_asset(
|
|
||||||
assetEthAddress,
|
|
||||||
amount + '0'.repeat(18),
|
|
||||||
'0x' + vegaWalletPubKey
|
|
||||||
),
|
|
||||||
{ timeout: transactionTimeout, log: false }
|
|
||||||
).then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('faucet_asset', function (assetEthAddress) {
|
|
||||||
cy.get('@signer', { log: false }).then((signer) => {
|
|
||||||
cy.wrap(new TokenFaucetable(assetEthAddress, signer), { log: false }).then(
|
|
||||||
(token) => {
|
|
||||||
cy.wrap(token.faucet(), {
|
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}).then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('vega_wallet_teardown', function () {
|
|
||||||
cy.get('aside [data-testid="associated-amount"]')
|
|
||||||
.should('be.visible')
|
|
||||||
.invoke('text')
|
|
||||||
.as('associatedAmount');
|
|
||||||
cy.get('body').then(($body) => {
|
|
||||||
if (
|
|
||||||
$body.find('[data-testid="eth-wallet-associated-balances"]').length ||
|
|
||||||
this.associatedAmount != '0.00'
|
|
||||||
) {
|
|
||||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
|
||||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cy.get(vegaWalletContainer).within(() => {
|
|
||||||
cy.get('[data-testid="associated-amount"]', { timeout: 30000 }).should(
|
|
||||||
'contain.text',
|
|
||||||
'0.00'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'vega_wallet_set_specified_approval_amount',
|
|
||||||
function (resetAmount) {
|
|
||||||
cy.highlight(`Setting token approval amount to ${resetAmount}`);
|
|
||||||
cy.wrap(new Token(vegaTokenAddress, this.signer), { log: false }).then(
|
|
||||||
(token) => {
|
|
||||||
cy.wrap(
|
|
||||||
token.approve(
|
|
||||||
ethStakingBridgeContractAddress,
|
|
||||||
resetAmount.concat('000000000000000000')
|
|
||||||
),
|
|
||||||
{ timeout: transactionTimeout, log: false }
|
|
||||||
).then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add(
|
|
||||||
'vega_wallet_teardown_staking',
|
|
||||||
(stakingBridgeContract) => {
|
|
||||||
cy.highlight('Tearing down staking tokens from vega wallet if present');
|
|
||||||
cy.wrap(
|
|
||||||
stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
|
||||||
{
|
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}
|
|
||||||
).then((stake_amount) => {
|
|
||||||
if (String(stake_amount) != '0') {
|
|
||||||
cy.wrap(
|
|
||||||
stakingBridgeContract.remove_stake(stake_amount, vegaWalletPubKey),
|
|
||||||
{ timeout: transactionTimeout, log: false }
|
|
||||||
).then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Cypress.Commands.add('vega_wallet_teardown_vesting', (vestingContract) => {
|
|
||||||
cy.highlight('Tearing down vesting tokens from vega wallet if present');
|
|
||||||
cy.wrap(vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), {
|
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}).then((vesting_amount) => {
|
|
||||||
if (String(vesting_amount) != '0') {
|
|
||||||
cy.wrap(vestingContract.remove_stake(vesting_amount, vegaWalletPubKey), {
|
|
||||||
timeout: transactionTimeout,
|
|
||||||
log: false,
|
|
||||||
}).then((tx) => {
|
|
||||||
cy.wait_for_transaction(tx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('vega_wallet_associate', (amount) => {
|
|
||||||
amount = amount + '0'.repeat(18);
|
|
||||||
cy.highlight('Associating tokens');
|
|
||||||
cy.get('@stakingBridgeContract').then((stakingBridgeContract) => {
|
|
||||||
stakingBridgeContract.stake(amount, vegaWalletPubKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('vega_wallet_disassociate', (amount) => {
|
|
||||||
amount = amount + '0'.repeat(18);
|
|
||||||
cy.highlight('Disassociating tokens');
|
|
||||||
cy.get('@stakingBridgeContract').then((stakingBridgeContract) => {
|
|
||||||
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('wait_for_transaction', (tx) => {
|
|
||||||
cy.wrap(tx.wait(1).catch(cy.log), { timeout: transactionTimeout });
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import { promiseWithTimeout } from '@vegaprotocol/cypress';
|
||||||
|
import {
|
||||||
|
StakingBridge,
|
||||||
|
Token,
|
||||||
|
TokenVesting,
|
||||||
|
TokenFaucetable,
|
||||||
|
CollateralBridge,
|
||||||
|
} from '@vegaprotocol/smart-contracts';
|
||||||
|
import { ethers, Wallet } from 'ethers';
|
||||||
|
|
||||||
|
const vegaWalletContainer = 'aside [data-testid="vega-wallet"]';
|
||||||
|
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
|
||||||
|
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||||
|
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
||||||
|
const vegaTokenAddress = Cypress.env('vegaTokenAddress');
|
||||||
|
const ethWalletPubKey = Cypress.env('ethWalletPublicKey');
|
||||||
|
const ethStakingBridgeContractAddress = Cypress.env(
|
||||||
|
'ethStakingBridgeContractAddress'
|
||||||
|
);
|
||||||
|
const ethProviderUrl = Cypress.env('ethProviderUrl');
|
||||||
|
const getAccount = (number = 0) => `m/44'/60'/0'/0/${number}`;
|
||||||
|
const transactionTimeout = 100000;
|
||||||
|
const Erc20BridgeAddress = '0x9708FF7510D4A7B9541e1699d15b53Ecb1AFDc54';
|
||||||
|
|
||||||
|
const provider = new ethers.providers.JsonRpcProvider({ url: ethProviderUrl });
|
||||||
|
const privateKey = Wallet.fromMnemonic(
|
||||||
|
vegaWalletMnemonic,
|
||||||
|
getAccount(0)
|
||||||
|
).privateKey;
|
||||||
|
const signer = new Wallet(privateKey, provider);
|
||||||
|
const stakingBridgeContract = new StakingBridge(
|
||||||
|
ethStakingBridgeContractAddress,
|
||||||
|
signer
|
||||||
|
);
|
||||||
|
const vestingContract = new TokenVesting(vegaTokenContractAddress, signer);
|
||||||
|
|
||||||
|
export async function depositAsset(assetEthAddress: string, amount: string) {
|
||||||
|
// Approve asset
|
||||||
|
const faucet = new TokenFaucetable(assetEthAddress, signer);
|
||||||
|
cy.wrap(faucet.approve(Erc20BridgeAddress, amount + '0'.repeat(19)), {
|
||||||
|
timeout: transactionTimeout,
|
||||||
|
log: false,
|
||||||
|
}).then(() => {
|
||||||
|
const collateralBridge = new CollateralBridge(Erc20BridgeAddress, signer);
|
||||||
|
cy.wrap(
|
||||||
|
collateralBridge.deposit_asset(
|
||||||
|
assetEthAddress,
|
||||||
|
amount + '0'.repeat(18),
|
||||||
|
'0x' + vegaWalletPubKey
|
||||||
|
),
|
||||||
|
{ timeout: transactionTimeout, log: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function faucetAsset(assetEthAddress: string) {
|
||||||
|
const faucet = new TokenFaucetable(assetEthAddress, signer);
|
||||||
|
await promiseWithTimeout(faucet.faucet(), 10 * 60 * 1000, 'faucet asset');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function vegaWalletTeardown() {
|
||||||
|
cy.get('[data-testid="associated-amount"]')
|
||||||
|
.should('be.visible')
|
||||||
|
.invoke('text')
|
||||||
|
.then((associatedAmount) => {
|
||||||
|
cy.get('body').then(($body) => {
|
||||||
|
if (
|
||||||
|
$body.find('[data-testid="eth-wallet-associated-balances"]').length ||
|
||||||
|
associatedAmount != '0.00'
|
||||||
|
) {
|
||||||
|
vegaWalletTeardownVesting(vestingContract);
|
||||||
|
vegaWalletTeardownStaking(stakingBridgeContract);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cy.get(vegaWalletContainer).within(() => {
|
||||||
|
cy.getByTestId('associated-amount', {
|
||||||
|
timeout: transactionTimeout,
|
||||||
|
}).contains('0.00', {
|
||||||
|
timeout: transactionTimeout,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function vegaWalletSetSpecifiedApprovalAmount(
|
||||||
|
resetAmount: string
|
||||||
|
) {
|
||||||
|
cy.highlight(`Setting token approval amount to ${resetAmount}`);
|
||||||
|
const token = new Token(vegaTokenAddress, signer);
|
||||||
|
await promiseWithTimeout(
|
||||||
|
token.approve(
|
||||||
|
ethStakingBridgeContractAddress,
|
||||||
|
resetAmount.concat('000000000000000000')
|
||||||
|
),
|
||||||
|
10 * 60 * 1000,
|
||||||
|
'set approval amount'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
|
||||||
|
cy.highlight('Tearing down staking tokens from vega wallet if present');
|
||||||
|
cy.wrap(
|
||||||
|
stakingBridgeContract.stake_balance(ethWalletPubKey, vegaWalletPubKey),
|
||||||
|
{ timeout: transactionTimeout, log: false }
|
||||||
|
).then((stakeBalance) => {
|
||||||
|
if (Number(stakeBalance) != 0) {
|
||||||
|
cy.wrap(
|
||||||
|
stakingBridgeContract.remove_stake(
|
||||||
|
String(stakeBalance),
|
||||||
|
vegaWalletPubKey
|
||||||
|
),
|
||||||
|
{ timeout: transactionTimeout, log: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function vegaWalletTeardownVesting(vestingContract: TokenVesting) {
|
||||||
|
cy.highlight('Tearing down vesting tokens from vega wallet if present');
|
||||||
|
cy.wrap(vestingContract.stake_balance(ethWalletPubKey, vegaWalletPubKey), {
|
||||||
|
timeout: transactionTimeout,
|
||||||
|
log: false,
|
||||||
|
}).then((vestingAmount) => {
|
||||||
|
if (Number(vestingAmount) != 0) {
|
||||||
|
// Wait needed to allow time for ganache to process tx for stakingBridgeContract.remove_stake
|
||||||
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.wrap(
|
||||||
|
vestingContract.remove_stake(String(vestingAmount), vegaWalletPubKey),
|
||||||
|
{ timeout: transactionTimeout, log: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function vegaWalletAssociate(amount: string) {
|
||||||
|
cy.highlight('Associating tokens');
|
||||||
|
amount = amount + '0'.repeat(18);
|
||||||
|
stakingBridgeContract.stake(amount, vegaWalletPubKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function vegaWalletDisassociate(amount: string) {
|
||||||
|
cy.highlight('Disassociating tokens');
|
||||||
|
amount = amount + '0'.repeat(18);
|
||||||
|
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
Cypress.Commands.add(
|
|
||||||
'vega_wallet_faucet_assets_without_check',
|
|
||||||
function (asset, amount, vegaWalletPublicKey) {
|
|
||||||
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,18 @@
|
|||||||
|
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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["es5", "dom", "es2021"],
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
|||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json
|
||||||
|
|
||||||
#Test configuration variables
|
#Test configuration variables
|
||||||
CYPRESS_FAIRGROUND=false
|
CYPRESS_FAIRGROUND=false
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
|||||||
NX_FAIRGROUND=false
|
NX_FAIRGROUND=false
|
||||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
NX_VEGA_CONFIG_URL=''
|
NX_VEGA_CONFIG_URL=''
|
||||||
|
|
||||||
NX_VEGA_URL=http://localhost:3028/query
|
NX_VEGA_URL=http://localhost:3028/query
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
|||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -11,3 +11,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
|||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
|||||||
NX_VEGA_EXPLORER_URL=https://mirror.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=https://mirror.explorer.vega.xyz
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json
|
||||||
@@ -6,3 +6,4 @@ NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-inter
|
|||||||
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -7,3 +7,4 @@ NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
|
|||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -8,3 +8,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
|||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
@@ -11,3 +11,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
|||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_DELEGATIONS_PAGINATION=50
|
NX_DELEGATIONS_PAGINATION=50
|
||||||
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
|
||||||
|
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
NX_VEGA_ENV=VALIDATOR_TESTNET
|
||||||
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks/master/testnet2/testnet2.toml
|
||||||
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
NX_VEGA_URL=https://api-validators-testnet.vega.rocks/graphql
|
||||||
NX_VEGA_REST=https://api.validators-testnet.vega.xyz/
|
NX_VEGA_REST=https://api-validators-testnet.vega.rocks/
|
||||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ const ConnectedKey = () => {
|
|||||||
</section>
|
</section>
|
||||||
<WalletCardActions>
|
<WalletCardActions>
|
||||||
<Link className="flex-1" to={Routes.ASSOCIATE}>
|
<Link className="flex-1" to={Routes.ASSOCIATE}>
|
||||||
<Button size="sm" fill={true}>
|
<Button data-testid="associate-btn" size="sm" fill={true}>
|
||||||
{t('associate')}
|
{t('associate')}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||||
ViewingAsBanner,
|
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||||
AnnouncementBanner,
|
|
||||||
ExternalLink,
|
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@@ -15,18 +12,16 @@ export interface TemplateSidebarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||||
const { VEGA_ENV } = useEnvironment();
|
const { VEGA_ENV, ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AnnouncementBanner>
|
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
<AnnouncementBanner
|
||||||
<span className="pr-4">Mainnet sim 3 is live!</span>
|
app="governance"
|
||||||
<ExternalLink href="https://fairground.wtf/">
|
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||||
Come help stress test the network
|
/>
|
||||||
</ExternalLink>
|
)}
|
||||||
</div>
|
|
||||||
</AnnouncementBanner>
|
|
||||||
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||||
{isReadOnly ? (
|
{isReadOnly ? (
|
||||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||||
|
|||||||
@@ -221,8 +221,9 @@
|
|||||||
"votePending": "Casting vote",
|
"votePending": "Casting vote",
|
||||||
"voteError": "Something went wrong, and your vote was not seen by the network",
|
"voteError": "Something went wrong, and your vote was not seen by the network",
|
||||||
"back": "back",
|
"back": "back",
|
||||||
"byTokenVote": "by Token vote",
|
"byTokenVote": "by token vote",
|
||||||
"byLiquidityVote": "by Liquidity vote",
|
"byLiquidityVote": "by liquidity vote",
|
||||||
|
"byLPVote": "by LP vote",
|
||||||
"youDidNotVote": "Voting has ended. You did not vote",
|
"youDidNotVote": "Voting has ended. You did not vote",
|
||||||
"voteState_Yes": "For",
|
"voteState_Yes": "For",
|
||||||
"voteState_No": "Against",
|
"voteState_No": "Against",
|
||||||
@@ -601,11 +602,14 @@
|
|||||||
"noValidators": "No validators",
|
"noValidators": "No validators",
|
||||||
"validator": "Validator",
|
"validator": "Validator",
|
||||||
"stake": "Stake",
|
"stake": "Stake",
|
||||||
|
"myStake": "My stake",
|
||||||
"stakeShare": "Stake share",
|
"stakeShare": "Stake share",
|
||||||
"stakedByOperator": "Staked by operator",
|
"stakedByOperator": "Staked by operator",
|
||||||
"stakedByDelegates": "Staked by delegates",
|
"stakedByDelegates": "Staked by delegates",
|
||||||
|
"stakedByMe": "Staked by me",
|
||||||
"totalStake": "Total stake",
|
"totalStake": "Total stake",
|
||||||
"pendingStake": "Pending stake",
|
"pendingStake": "Pending stake",
|
||||||
|
"myPendingStake": "My pending stake",
|
||||||
"totalPenalties": "Total penalties",
|
"totalPenalties": "Total penalties",
|
||||||
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
|
"noPenaltyDataFromLastEpoch": "No penalty data from last epoch",
|
||||||
"stakeNeededForPromotion": "Stake needed for promotion",
|
"stakeNeededForPromotion": "Stake needed for promotion",
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
|
|||||||
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
|
||||||
import Routes from '../routes';
|
import Routes from '../routes';
|
||||||
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
import { useNodesQuery } from '../staking/home/__generated___/Nodes';
|
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
|
||||||
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
|
||||||
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
|
import { getNotRejectedProposals } from '../proposals/proposals/proposals-container';
|
||||||
import { Heading } from '../../components/heading';
|
import { Heading } from '../../components/heading';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { RouteChildProps } from '..';
|
import type { RouteChildProps } from '..';
|
||||||
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
|
import type { ProposalFieldsFragment } from '../proposals/proposals/__generated__/Proposals';
|
||||||
import type { NodesFragmentFragment } from '../staking/home/__generated___/Nodes';
|
import type { NodesFragmentFragment } from '../staking/home/__generated__/Nodes';
|
||||||
|
|
||||||
const nodesToShow = 6;
|
const nodesToShow = 6;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -86,7 +86,7 @@ describe('Proposal Votes Table', () => {
|
|||||||
|
|
||||||
it('displays if an update market proposal will pass by token vote', () => {
|
it('displays if an update market proposal will pass by token vote', () => {
|
||||||
renderComponent(updateMarketProposal, updateMarketProposalType);
|
renderComponent(updateMarketProposal, updateMarketProposalType);
|
||||||
expect(screen.getByText('👍 by Token vote')).toBeInTheDocument();
|
expect(screen.getByText('👍 by token vote')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays if an update market proposal will pass by LP vote', () => {
|
it('displays if an update market proposal will pass by LP vote', () => {
|
||||||
@@ -110,6 +110,6 @@ describe('Proposal Votes Table', () => {
|
|||||||
}),
|
}),
|
||||||
updateMarketProposalType
|
updateMarketProposalType
|
||||||
);
|
);
|
||||||
expect(screen.getByText('👍 by Liquidity vote')).toBeInTheDocument();
|
expect(screen.getByText('👍 by liquidity vote')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+76
@@ -136,6 +136,82 @@ describe('Proposals list item details', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Renders proposal state: Update market proposal - set to pass by LP vote', () => {
|
||||||
|
renderComponent(
|
||||||
|
generateProposal({
|
||||||
|
state: ProposalState.STATE_OPEN,
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
...generateYesVotes(0),
|
||||||
|
totalEquityLikeShareWeight: '1000',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
...generateNoVotes(0),
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('vote-status')).toHaveTextContent(
|
||||||
|
'Set to pass by LP vote'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders proposal state: Update market proposal - set to pass by token vote', () => {
|
||||||
|
renderComponent(
|
||||||
|
generateProposal({
|
||||||
|
state: ProposalState.STATE_OPEN,
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
...generateYesVotes(1000, 1000),
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
...generateNoVotes(0),
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('vote-status')).toHaveTextContent(
|
||||||
|
'Set to pass by token vote'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Renders proposal state: Update market proposal - set to fail', () => {
|
||||||
|
renderComponent(
|
||||||
|
generateProposal({
|
||||||
|
state: ProposalState.STATE_OPEN,
|
||||||
|
terms: {
|
||||||
|
change: {
|
||||||
|
__typename: 'UpdateMarket',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
votes: {
|
||||||
|
yes: {
|
||||||
|
...generateYesVotes(0),
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
|
},
|
||||||
|
no: {
|
||||||
|
...generateNoVotes(0),
|
||||||
|
totalEquityLikeShareWeight: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('vote-status')).toHaveTextContent('Set to fail');
|
||||||
|
});
|
||||||
|
|
||||||
it('Renders proposal state: Open - 5 minutes left to vote', () => {
|
it('Renders proposal state: Open - 5 minutes left to vote', () => {
|
||||||
renderComponent(
|
renderComponent(
|
||||||
generateProposal({
|
generateProposal({
|
||||||
|
|||||||
+27
-4
@@ -41,12 +41,22 @@ export const ProposalsListItemDetails = ({
|
|||||||
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
|
||||||
}) => {
|
}) => {
|
||||||
const state = proposal?.state;
|
const state = proposal?.state;
|
||||||
const { willPassByTokenVote, majorityMet, participationMet } =
|
const {
|
||||||
useVoteInformation({
|
willPassByTokenVote,
|
||||||
proposal,
|
willPassByLPVote,
|
||||||
});
|
majorityMet,
|
||||||
|
participationMet,
|
||||||
|
} = useVoteInformation({
|
||||||
|
proposal,
|
||||||
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { voteState } = useUserVote(proposal?.id);
|
const { voteState } = useUserVote(proposal?.id);
|
||||||
|
const isUpdateMarket = proposal?.terms.change.__typename === 'UpdateMarket';
|
||||||
|
const updateMarketWillPass = willPassByTokenVote || willPassByLPVote;
|
||||||
|
const updateMarketVotePassMethod = willPassByTokenVote
|
||||||
|
? t('byTokenVote')
|
||||||
|
: t('byLPVote');
|
||||||
|
|
||||||
let proposalStatus: ReactNode;
|
let proposalStatus: ReactNode;
|
||||||
let voteDetails: ReactNode;
|
let voteDetails: ReactNode;
|
||||||
let voteStatus: ReactNode;
|
let voteStatus: ReactNode;
|
||||||
@@ -128,6 +138,19 @@ export const ProposalsListItemDetails = ({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
voteStatus =
|
voteStatus =
|
||||||
|
(isUpdateMarket &&
|
||||||
|
(updateMarketWillPass ? (
|
||||||
|
<>
|
||||||
|
{t('Set to')}{' '}
|
||||||
|
<StatusPass>
|
||||||
|
{t('pass')} {updateMarketVotePassMethod}
|
||||||
|
</StatusPass>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{t('Set to')} <StatusFail>{t('fail')}</StatusFail>
|
||||||
|
</>
|
||||||
|
))) ||
|
||||||
(!participationMet && <ParticipationNotReached />) ||
|
(!participationMet && <ParticipationNotReached />) ||
|
||||||
(!majorityMet && <MajorityNotReached />) ||
|
(!majorityMet && <MajorityNotReached />) ||
|
||||||
(willPassByTokenVote ? (
|
(willPassByTokenVote ? (
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export const VoteDetails = ({
|
|||||||
totalTokensPercentage,
|
totalTokensPercentage,
|
||||||
participationMet,
|
participationMet,
|
||||||
totalTokensVoted,
|
totalTokensVoted,
|
||||||
|
totalLPTokensPercentage,
|
||||||
noPercentage,
|
noPercentage,
|
||||||
noLPPercentage,
|
noLPPercentage,
|
||||||
yesPercentage,
|
yesPercentage,
|
||||||
@@ -41,6 +42,8 @@ export const VoteDetails = ({
|
|||||||
requiredMajorityPercentage,
|
requiredMajorityPercentage,
|
||||||
requiredMajorityLPPercentage,
|
requiredMajorityLPPercentage,
|
||||||
requiredParticipation,
|
requiredParticipation,
|
||||||
|
requiredParticipationLP,
|
||||||
|
participationLPMet,
|
||||||
} = useVoteInformation({ proposal });
|
} = useVoteInformation({ proposal });
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -101,6 +104,25 @@ export const VoteDetails = ({
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<p className="mb-6">
|
||||||
|
{t('participation')}
|
||||||
|
{': '}
|
||||||
|
{participationLPMet ? (
|
||||||
|
<span className="text-vega-green mx-4">{t('met')}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-danger mx-4">{t('notMet')}</span>
|
||||||
|
)}{' '}
|
||||||
|
{formatNumber(totalLPTokensPercentage, defaultDecimals)}%
|
||||||
|
<span className="ml-4">
|
||||||
|
{requiredParticipationLP && (
|
||||||
|
<>
|
||||||
|
({formatNumber(requiredParticipationLP, defaultDecimals)}%{' '}
|
||||||
|
{t('governanceRequired')})
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
<section data-testid="votes-table">
|
<section data-testid="votes-table">
|
||||||
|
|||||||
@@ -16,12 +16,8 @@ import orderBy from 'lodash/orderBy';
|
|||||||
const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
const orderByDate = (arr: ProposalFieldsFragment[]) =>
|
||||||
orderBy(
|
orderBy(
|
||||||
arr,
|
arr,
|
||||||
[
|
[(p) => new Date(p?.terms?.closingDatetime).getTime(), (p) => p.id],
|
||||||
(p) => new Date(p?.terms?.enactmentDatetime || 0).getTime(), // has to be defaulted to 0 because new Date(null).getTime() -> NaN which is first when ordered.
|
['desc', 'desc']
|
||||||
(p) => new Date(p?.terms?.closingDatetime).getTime(),
|
|
||||||
(p) => p.id,
|
|
||||||
],
|
|
||||||
['desc', 'desc', 'desc']
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
export function getNotRejectedProposals<T extends ProposalFieldsFragment>(
|
||||||
|
|||||||
+6
@@ -21,6 +21,12 @@ export const EpochIndividualRewards = () => {
|
|||||||
first: Number(delegationsPagination),
|
first: Number(delegationsPagination),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
// we can use the same value for rewardsPagination as delegationsPagination
|
||||||
|
rewardsPagination: delegationsPagination
|
||||||
|
? {
|
||||||
|
first: Number(delegationsPagination),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
skip: !pubKey,
|
skip: !pubKey,
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user