Compare commits

..
Author SHA1 Message Date
Matthew Russell c627dd2cf5 chore: fix lint 2023-06-29 11:16:52 -07:00
Matthew Russell db4ce3b5bc chore: change to use vega icons for dropdowns and withdrawals table 2023-06-29 11:16:52 -07:00
Madalina Raicu d3df339696 chore(trading,governance,explorer): release update to vv0.20.19-core-0.71.6 2023-06-29 16:51:57 +03:00
Sam Keen a31008ea26 feat(governance): improve asset proposal details view (#4216) 2023-06-29 14:41:25 +01:00
Edd 5e93e98f07 fix(explorer): fix order amend tx view (#4197) 2023-06-29 12:25:42 +01:00
Ciaran McGhie bf3ff8fb6f fix(ui-toolkit): healthbar tooltips text colour (#4199) 2023-06-29 12:25:14 +01:00
Bartłomiej Głownia 16538ca3a3 feat(trading): show fills across all markets (#4210) 2023-06-29 12:24:51 +01:00
Edd 2fa00dacaa test(governance,markets): tidy up minor test quibbles (#4213) 2023-06-29 11:20:53 +00:00
Ben 45b7c2ad4d test(trading): 6004-CHAR-chart e2e tests (#4179) 2023-06-29 09:14:54 +01:00
Sam Keen ed2c82487d feat(governance): add toggle for closed proposals list (#4190) 2023-06-28 17:53:01 +01:00
Joe Tsang 55143331f1 test(governance): fix staking tooltip test (#4198) 2023-06-28 17:15:06 +01:00
Davide SandEdd cafb3b1c57 fix(explorer): liquidity provision fee percentage (#4183)
Co-authored-by: Edd <edd@vega.xyz>
2023-06-28 15:35:38 +00:00
Mikołaj Młodzikowski 019b2d7d89 feat(ci): fix brakcets 2023-06-28 15:12:03 +02:00
Mikołaj Młodzikowski de0dc4af8e feat(ci): do not check empty arrays 2023-06-28 15:09:17 +02:00
Mikołaj Młodzikowski 6765f4d03a feat: add logic for testing against pull_request_target 2023-06-28 15:06:01 +02:00
Mikołaj Młodzikowski 7bea90e4d1 fix(ci): use jq to generate valid json arrays from bash (#4205) 2023-06-28 14:54:25 +02:00
67 changed files with 1847 additions and 656 deletions
+4 -4
View File
@@ -49,7 +49,7 @@ jobs:
lint-pr-title:
needs: node-modules
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
name: Verify PR title
uses: ./.github/workflows/lint-pr.yml
secrets: inherit
@@ -204,7 +204,7 @@ jobs:
cypress:
needs: lint-test-build
name: '(CI) cypress'
if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
# if: ${{ needs.lint-test-build.outputs.projects-e2e != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
@@ -214,7 +214,7 @@ jobs:
publish-dist:
needs: lint-test-build
name: '(CD) publish dist'
if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
# if: ${{ needs.lint-test-build.outputs.projects != '[]' }}
uses: ./.github/workflows/publish-dist.yml
secrets: inherit
with:
@@ -225,7 +225,7 @@ jobs:
needs:
- publish-dist
- lint-test-build
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
timeout-minutes: 60
name: '(CD) comment preview links'
steps:
+4 -4
View File
@@ -33,7 +33,7 @@ jobs:
uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry (ghcr)
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
uses: docker/login-action@v2
with:
registry: ghcr.io
@@ -145,7 +145,7 @@ jobs:
ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local
- name: Image digest
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
run: echo ${{ steps.docker_build.outputs.digest }}
- name: Sanity check docker image
@@ -160,7 +160,7 @@ jobs:
uses: docker/build-push-action@v3
continue-on-error: true
id: ghcr-push
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
with:
context: .
file: docker/node-outside-docker.Dockerfile
@@ -230,7 +230,7 @@ jobs:
- name: Add preview label
uses: actions-ecosystem/action-add-labels@v1
if: ${{ github.event_name == 'pull_request' }}
if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
with:
labels: ${{ matrix.app }}-preview
number: ${{ github.event.number }}
@@ -12,7 +12,7 @@ type Amend = components['schemas']['v1OrderAmendment'];
function renderAmendOrderDetails(
id: string,
version: number,
version: number | undefined,
amend: Amend,
mocks: MockedResponse[]
) {
@@ -25,7 +25,11 @@ function renderAmendOrderDetails(
);
}
function renderExistingAmend(id: string, version: number, amend: Amend) {
function renderExistingAmend(
id: string,
version: number | undefined,
amend: Amend
) {
const mocks = [
{
request: {
@@ -77,6 +81,55 @@ function renderExistingAmend(id: string, version: number, amend: Amend) {
},
},
},
{
request: {
query: ExplorerDeterministicOrderDocument,
variables: {
orderId: '123',
},
},
result: {
data: {
orderByID: {
__typename: 'Order',
id: '123',
type: 'GTT',
status: Schema.OrderStatus.STATUS_ACTIVE,
version: 100,
createdAt: '123',
updatedAt: '456',
expiresAt: '789',
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
price: '200',
side: 'BUY',
remaining: '99',
rejectionReason: 'rejection',
reference: '123',
size: '200',
party: {
__typename: 'Party',
id: '234',
},
market: {
__typename: 'Market',
id: 'amend-to-order-latest-version',
state: 'STATUS_ACTIVE',
positionDecimalPlaces: 2,
decimalPlaces: '5',
tradableInstrument: {
instrument: {
name: 'amend-to-order-latest-version-test',
product: {
__typename: 'Future',
quoteName: '123',
},
},
},
},
},
},
},
},
{
request: {
query: ExplorerMarketDocument,
@@ -157,4 +210,15 @@ describe('Amend order details', () => {
expect(await res.findByText('New price')).toBeInTheDocument();
expect(await res.findByText('-7879')).toBeInTheDocument();
});
it('Fetches latest version when version is not specified', async () => {
const amend: Amend = {
price: '-7879',
};
const res = renderExistingAmend('123', undefined, amend);
expect(
await res.findByText('amend-to-order-latest-version')
).toBeInTheDocument();
});
});
@@ -12,7 +12,7 @@ import { wrapperClasses } from './deterministic-order-details';
export interface AmendOrderDetailsProps {
id: string;
amend: components['schemas']['v1OrderAmendment'];
// Version to fetch, with 0 being 'latest' and 1 being 'first'. Defaults to 0
// Version to fetch. Latest is provided by default
version?: number;
}
@@ -34,13 +34,11 @@ export function getSideDeltaColour(delta: string): string {
* @param param0
* @returns
*/
const AmendOrderDetails = ({
id,
version = 0,
amend,
}: AmendOrderDetailsProps) => {
const AmendOrderDetails = ({ id, version, amend }: AmendOrderDetailsProps) => {
const variables = version ? { orderId: id, version } : { orderId: id };
const { data, error } = useExplorerDeterministicOrderQuery({
variables: { orderId: id, version },
variables,
});
if (error || (data && !data.orderByID)) {
@@ -0,0 +1,86 @@
import { render } from '@testing-library/react';
import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
describe('TxDetailsLiquidityAmendment', () => {
const mockTxData = {
hash: 'test',
command: {
liquidityProvisionAmendment: {
marketId: 'BTC-USD',
commitmentAmount: 100,
fee: '0.01',
},
},
};
const mockPubKey = '123';
const mockBlockData = {
result: {
block: {
header: {
height: '123',
},
},
},
};
it('should render the component with correct data', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={mockTxData as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(getByText('Market')).toBeInTheDocument();
expect(getByText('BTC-USD')).toBeInTheDocument();
expect(getByText('Commitment amount')).toBeInTheDocument();
expect(getByText('100')).toBeInTheDocument();
expect(getByText('Fee')).toBeInTheDocument();
expect(getByText('1%')).toBeInTheDocument();
});
it('should display awaiting message when tx data is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={undefined}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
it('should display awaiting message when liquidityProvisionAmendment is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquidityAmendment
txData={{ command: {} } as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
});
@@ -7,6 +7,7 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
import type { components } from '../../../../types/explorer';
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
import PriceInMarket from '../../price-in-market/price-in-market';
import BigNumber from 'bignumber.js';
export type LiquidityAmendment =
components['schemas']['v1LiquidityProvisionAmendment'];
@@ -34,6 +35,10 @@ export const TxDetailsLiquidityAmendment = ({
txData.command.liquidityProvisionAmendment;
const marketId: string = amendment.marketId || '-';
const fee = amendment.fee
? new BigNumber(amendment.fee).times(100).toString()
: '-';
return (
<>
<TableWithTbody className="mb-8" allowWrap={true}>
@@ -63,7 +68,7 @@ export const TxDetailsLiquidityAmendment = ({
{amendment.fee ? (
<TableRow modifier="bordered">
<TableCell>{t('Fee')}</TableCell>
<TableCell>{amendment.fee}%</TableCell>
<TableCell>{fee}%</TableCell>
</TableRow>
) : null}
</TableWithTbody>
@@ -0,0 +1,86 @@
import { render } from '@testing-library/react';
import { TxDetailsLiquiditySubmission } from './tx-liquidity-submission';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter } from 'react-router-dom';
describe('TxDetailsLiquiditySubmission', () => {
const mockTxData = {
hash: 'test',
command: {
liquidityProvisionSubmission: {
marketId: 'BTC-USD',
commitmentAmount: 100,
fee: '0.01',
},
},
};
const mockPubKey = '123';
const mockBlockData = {
result: {
block: {
header: {
height: '123',
},
},
},
};
it('should render the component with correct data', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={mockTxData as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(getByText('Market')).toBeInTheDocument();
expect(getByText('BTC-USD')).toBeInTheDocument();
expect(getByText('Commitment amount')).toBeInTheDocument();
expect(getByText('100')).toBeInTheDocument();
expect(getByText('Fee')).toBeInTheDocument();
expect(getByText('1%')).toBeInTheDocument();
});
it('should display awaiting message when tx data is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={undefined}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
it('should display awaiting message when liquidityProvisionSubmission is undefined', () => {
const { getByText } = render(
<MockedProvider>
<MemoryRouter>
<TxDetailsLiquiditySubmission
txData={{ command: {} } as BlockExplorerTransactionResult}
pubKey={mockPubKey}
blockData={mockBlockData as TendermintBlocksResponse}
/>
</MemoryRouter>
</MockedProvider>
);
expect(
getByText('Awaiting Block Explorer transaction details')
).toBeInTheDocument();
});
});
@@ -7,6 +7,7 @@ import { TableCell, TableRow, TableWithTbody } from '../../table';
import type { components } from '../../../../types/explorer';
import { LiquidityProvisionDetails } from './liquidity-provision/liquidity-provision-details';
import PriceInMarket from '../../price-in-market/price-in-market';
import BigNumber from 'bignumber.js';
export type LiquiditySubmission =
components['schemas']['v1LiquidityProvisionSubmission'];
@@ -33,6 +34,10 @@ export const TxDetailsLiquiditySubmission = ({
txData.command.liquidityProvisionSubmission;
const marketId: string = submission.marketId || '-';
const fee = submission.fee
? new BigNumber(submission.fee).times(100).toString()
: '-';
return (
<>
<TableWithTbody className="mb-8" allowWrap={true}>
@@ -62,7 +67,7 @@ export const TxDetailsLiquiditySubmission = ({
{submission.fee ? (
<TableRow modifier="bordered">
<TableCell>{t('Fee')}</TableCell>
<TableCell>{submission.fee}%</TableCell>
<TableCell>{fee}%</TableCell>
</TableRow>
) : null}
</TableWithTbody>
@@ -28,18 +28,17 @@ import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
const proposalVoteProgressForPercentage =
'[data-testid="vote-progress-indicator-percentage-for"]';
'vote-progress-indicator-percentage-for';
const proposalVoteProgressAgainstPercentage =
'[data-testid="vote-progress-indicator-percentage-against"]';
const proposalVoteProgressForTokens =
'[data-testid="vote-progress-indicator-tokens-for"]';
'vote-progress-indicator-percentage-against';
const proposalVoteProgressForTokens = 'vote-progress-indicator-tokens-for';
const proposalVoteProgressAgainstTokens =
'[data-testid="vote-progress-indicator-tokens-against"]';
const changeVoteButton = '[data-testid="change-vote-button"]';
const proposalDetailsTitle = '[data-testid="proposal-title"]';
const proposalDetailsDescription = '[data-testid="proposal-description"]';
const openProposals = '[data-testid="open-proposals"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
'vote-progress-indicator-tokens-against';
const changeVoteButton = 'change-vote-button';
const proposalDetailsTitle = 'proposal-title';
const proposalDetailsDescription = 'proposal-description';
const openProposals = 'open-proposals';
const viewProposalButton = 'view-proposal-btn';
const proposalDescriptionToggle = 'proposal-description-toggle';
const voteBreakdownToggle = 'vote-breakdown-toggle';
const proposalTermsToggle = 'proposal-json-toggle';
@@ -72,18 +71,18 @@ describe(
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
cy.get(openProposals).within(() => {
cy.getByTestId(openProposals).within(() => {
getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.get(viewProposalButton).should('be.visible').click();
cy.getByTestId(viewProposalButton).should('be.visible').click();
});
});
cy.get(proposalDetailsTitle).should(
cy.getByTestId(proposalDetailsTitle).should(
'contain.text',
rawProposal.rationale.title
);
cy.getByTestId(proposalDescriptionToggle).click();
cy.getByTestId('proposal-description-toggle');
cy.get(proposalDetailsDescription)
cy.getByTestId(proposalDetailsDescription)
.find('p')
.should('have.text', proposalDescription);
});
@@ -117,7 +116,7 @@ describe(
});
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
cy.wrap(
formatDateWithLocalTimezone(new Date(proposalTimeStamp * 1000))
@@ -139,7 +138,7 @@ describe(
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
});
cy.contains('Participation: Not Met 0.00 0.00%(0.00% Required)').should(
@@ -166,7 +165,7 @@ describe(
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
});
// 3001-VOTE-080
@@ -183,14 +182,16 @@ describe(
.contains(votedDate)
.should('be.visible');
});
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
cy.getByTestId(proposalVoteProgressForPercentage) // 3001-VOTE-072
.contains('100.00%')
.and('be.visible');
cy.get(proposalVoteProgressAgainstPercentage)
cy.getByTestId(proposalVoteProgressAgainstPercentage)
.contains('0.00%')
.and('be.visible');
cy.get(proposalVoteProgressForTokens).contains('1.00').and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
cy.getByTestId(proposalVoteProgressForTokens)
.contains('1.00')
.and('be.visible');
cy.getByTestId(proposalVoteProgressAgainstTokens)
.contains('0.00')
.and('be.visible');
cy.getByTestId(voteBreakdownToggle).click();
@@ -211,15 +212,15 @@ describe(
getProposalInformationFromTable('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
cy.get(changeVoteButton).should('be.visible').click();
cy.getByTestId(changeVoteButton).should('be.visible').click();
voteForProposal('for');
// 3001-VOTE-064
getProposalInformationFromTable('Tokens for proposal')
.should('have.text', (1).toFixed(2))
.and('be.visible');
cy.get(changeVoteButton).should('be.visible').click();
cy.getByTestId(changeVoteButton).should('be.visible').click();
voteForProposal('against');
cy.get(proposalVoteProgressAgainstPercentage)
cy.getByTestId(proposalVoteProgressAgainstPercentage)
.contains('100.00%')
.and('be.visible');
getProposalInformationFromTable('Tokens against proposal')
@@ -236,13 +237,15 @@ describe(
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
});
voteForProposal('for');
// 3001-VOTE-079
cy.contains('You voted: For').should('be.visible');
cy.get(proposalVoteProgressForTokens).contains('1').and('be.visible');
cy.getByTestId(proposalVoteProgressForTokens)
.contains('1')
.and('be.visible');
cy.getByTestId(voteBreakdownToggle).click();
getProposalInformationFromTable('Total Supply')
.invoke('text')
@@ -258,22 +261,22 @@ describe(
navigateTo(navigation.proposals);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
});
cy.get(proposalVoteProgressForPercentage)
cy.getByTestId(proposalVoteProgressForPercentage)
.contains('100.00%')
.and('be.visible');
cy.get(proposalVoteProgressAgainstPercentage)
cy.getByTestId(proposalVoteProgressAgainstPercentage)
.contains('0.00%')
.and('be.visible');
// 3001-VOTE-065
cy.get(changeVoteButton).should('be.visible').click();
cy.getByTestId(changeVoteButton).should('be.visible').click();
voteForProposal('for');
cy.get(proposalVoteProgressForTokens)
cy.getByTestId(proposalVoteProgressForTokens)
.contains(tokensRequiredToAchieveResult)
.and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
cy.getByTestId(proposalVoteProgressAgainstTokens)
.contains('0.00')
.and('be.visible');
cy.getByTestId(voteBreakdownToggle).click();
@@ -310,7 +313,7 @@ describe(
createRawProposal();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
voteForProposal('for');
cy.contains('You voted: For').should('be.visible');
@@ -319,13 +322,16 @@ describe(
stakingPageAssociateTokens('2');
navigateTo(navigation.proposals);
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
cy.getByTestId('you-voted').should('not.exist');
voteForProposal('against');
cy.contains('You voted: Against').should('be.visible');
switchVegaWalletPubKey();
cy.get(proposalVoteProgressForTokens).should('contain.text', '1.00');
cy.getByTestId(proposalVoteProgressForTokens).should(
'contain.text',
'1.00'
);
// Checking vote status for different public keys is displayed correctly
cy.contains('You voted: For').should('be.visible');
});
@@ -19,13 +19,13 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
const proposalListItem = '[data-testid="proposals-list-item"]';
const closedProposals = '[data-testid="closed-proposals"]';
const proposalStatus = '[data-testid="proposal-status"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
const votesTable = '[data-testid="votes-table"]';
const openProposals = '[data-testid="open-proposals"]';
const closedProposals = 'closed-proposals';
const proposalStatus = 'proposal-status';
const viewProposalButton = 'view-proposal-btn';
const votesTable = 'votes-table';
const openProposals = 'open-proposals';
const proposalVoteProgressForPercentage =
'[data-testid="vote-progress-indicator-percentage-for"]';
'vote-progress-indicator-percentage-for';
const proposalTimeout = { timeout: 8000 };
context(
@@ -55,18 +55,18 @@ context(
cy.createMarket();
cy.reload();
waitForSpinner();
cy.get(closedProposals).within(() => {
cy.getByTestId(closedProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.get(proposalStatus).should('have.text', 'Enacted');
cy.get(viewProposalButton).click();
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
cy.getByTestId(viewProposalButton).click();
});
});
cy.getByTestId('proposal-type').should('have.text', 'New market');
cy.get(proposalStatus).should('have.text', 'Enacted');
cy.get(votesTable).within(() => {
cy.getByTestId(proposalStatus).should('have.text', 'Enacted');
cy.getByTestId(votesTable).within(() => {
cy.contains('Vote passed.').should('be.visible');
cy.contains('Voting has ended.').should('be.visible');
});
@@ -81,27 +81,27 @@ context(
navigateTo(navigation.proposals);
cy.reload();
waitForSpinner();
cy.get(openProposals).within(() => {
cy.getByTestId(openProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
.within(() => cy.getByTestId(viewProposalButton).click());
});
cy.get(proposalStatus).should('have.text', 'Open');
cy.getByTestId(proposalStatus).should('have.text', 'Open');
voteForProposal('for');
cy.get(proposalStatus, proposalTimeout)
cy.getByTestId(proposalStatus, proposalTimeout)
.should('have.text', 'Passed')
.then(() => {
cy.get(proposalStatus, proposalTimeout).should(
cy.getByTestId(proposalStatus, proposalTimeout).should(
'have.text',
'Enacted'
);
});
cy.get(votesTable).within(() => {
cy.getByTestId(votesTable).within(() => {
cy.contains('Vote passed.').should('be.visible');
cy.contains('Voting has ended.').should('be.visible');
});
cy.get(proposalVoteProgressForPercentage)
cy.getByTestId(proposalVoteProgressForPercentage)
.contains('100.00%')
.and('be.visible');
});
@@ -115,15 +115,18 @@ context(
navigateTo(navigation.proposals);
cy.reload();
waitForSpinner();
cy.get(openProposals, { timeout: 6000 }).within(() => {
cy.getByTestId(openProposals, { timeout: 6000 }).within(() => {
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
.within(() => cy.getByTestId(viewProposalButton).click());
});
cy.get(proposalStatus).should('have.text', 'Open');
cy.getByTestId(proposalStatus).should('have.text', 'Open');
voteForProposal('for');
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Enacted');
cy.getByTestId(proposalStatus, proposalTimeout).should(
'have.text',
'Enacted'
);
});
// 3001-VOTE-048 3001-VOTE-049 3001-VOTE-050
@@ -134,14 +137,17 @@ context(
navigateTo(navigation.proposals);
cy.reload();
waitForSpinner();
cy.get(openProposals).within(() => {
cy.getByTestId(openProposals).within(() => {
cy.contains(proposalTitle)
.parentsUntil(proposalListItem)
.last()
.within(() => cy.get(viewProposalButton).click());
.within(() => cy.getByTestId(viewProposalButton).click());
});
cy.get(proposalStatus).should('have.text', 'Open');
cy.get(proposalStatus, proposalTimeout).should('have.text', 'Declined');
cy.getByTestId(proposalStatus).should('have.text', 'Open');
cy.getByTestId(proposalStatus, proposalTimeout).should(
'have.text',
'Declined'
);
getProposalInformationFromTable('Rejection reason')
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
.and('be.visible');
@@ -36,20 +36,19 @@ import {
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import type { testFreeformProposal } from '../../support/common-interfaces';
const vegaWalletStakedBalances =
'[data-testid="vega-wallet-balance-staked-validators"]';
const vegaWalletAssociatedBalance = '[data-testid="associated-amount"]';
const vegaWalletNameElement = '[data-testid="wallet-name"]';
const vegaWallet = '[data-testid="vega-wallet"]';
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
const rawProposalData = '[data-testid="proposal-data"]';
const voteButtons = '[data-testid="vote-buttons"]';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
const vegaWalletAssociatedBalance = 'associated-amount';
const vegaWalletNameElement = 'wallet-name';
const vegaWallet = 'vega-wallet';
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
const newProposalSubmitButton = 'proposal-submit';
const viewProposalButton = 'view-proposal-btn';
const rawProposalData = 'proposal-data';
const voteButtons = 'vote-buttons';
const rejectProposalsLink = '[href="/proposals/rejected"]';
const feedbackError = '[data-testid="Error"]';
const noOpenProposals = '[data-testid="no-open-proposals"]';
const noClosedProposals = '[data-testid="no-closed-proposals"]';
const feedbackError = 'Error';
const noOpenProposals = 'no-open-proposals';
const noClosedProposals = 'no-closed-proposals';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
@@ -93,10 +92,10 @@ context(
// Test can only pass if run before other proposal tests.
it.skip('Should be able to see that no proposals exist', function () {
// 3001-VOTE-003
cy.get(noOpenProposals)
cy.getByTestId(noOpenProposals)
.should('be.visible')
.and('have.text', 'There are no open or yet to enact proposals');
cy.get(noClosedProposals)
cy.getByTestId(noClosedProposals)
.should('be.visible')
.and('have.text', 'There are no enacted or rejected proposals');
});
@@ -126,7 +125,10 @@ context(
stakingValidatorPageAddStake('2');
closeStakingDialog();
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
cy.getByTestId(vegaWalletStakedBalances, txTimeout).should(
'contain',
'2'
);
createRawProposal();
});
@@ -168,7 +170,7 @@ context(
getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.contains('Rejected').should('be.visible');
cy.contains('Close time too late').should('be.visible');
cy.get(viewProposalButton).click();
cy.getByTestId(viewProposalButton).click();
});
});
cy.getByTestId('proposal-status').should('have.text', 'Rejected');
@@ -185,14 +187,14 @@ context(
const errorMsg =
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)';
vegaWalletTeardown();
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
'0.00',
txTimeout
);
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should('have.text', errorMsg);
cy.getByTestId(feedbackError).should('have.text', errorMsg);
closeDialog();
});
@@ -205,7 +207,7 @@ context(
goToMakeNewProposal(governanceProposalType.RAW);
enterRawProposalBody(createTenDigitUnixTimeStampForSpecifiedDays(8));
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should('have.text', errorMsg);
cy.getByTestId(feedbackError).should('have.text', errorMsg);
closeDialog();
});
@@ -221,17 +223,17 @@ context(
createTenDigitUnixTimeStampForSpecifiedDays(8);
freeformProposal.unexpected = `i shouldn't be here`;
const proposalPayload = JSON.stringify(freeformProposal);
cy.get(rawProposalData).type(proposalPayload, {
cy.getByTestId(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should('have.text', errorMsg);
cy.getByTestId(feedbackError).should('have.text', errorMsg);
closeDialog();
cy.get(rawProposalData)
cy.getByTestId(rawProposalData)
.invoke('val')
.should('contain', "i shouldn't be here");
});
@@ -249,15 +251,15 @@ context(
rawProposal.terms.unexpectedField = `i shouldn't be here`;
const proposalPayload = JSON.stringify(rawProposal);
cy.get(rawProposalData).type(proposalPayload, {
cy.getByTestId(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError).should('have.text', errorMsg);
cy.getByTestId(feedbackError).should('have.text', errorMsg);
closeDialog();
});
@@ -265,10 +267,10 @@ context(
// 3006-PASC-006 3006-PASC-007 3008-PFRO-018 3008-PFRO-019 3003-PMAN-006 3003-PMAN-007
it('Unable to submit proposal without valid json', function () {
goToMakeNewProposal(governanceProposalType.RAW);
cy.get(newProposalSubmitButton).click();
cy.getByTestId(newProposalSubmitButton).click();
cy.getByTestId('input-error-text').should('have.text', 'Required');
cy.get(rawProposalData).type('Not a valid json string');
cy.get(newProposalSubmitButton).click();
cy.getByTestId(rawProposalData).type('Not a valid json string');
cy.getByTestId(newProposalSubmitButton).click();
cy.getByTestId('input-error-text').should(
'have.text',
'Must be valid JSON'
@@ -283,22 +285,22 @@ context(
submitUniqueRawProposal({ proposalTitle: proposalTitle });
ethereumWalletConnect();
stakingPageDisassociateTokens('0.0001');
cy.get(vegaWallet)
cy.getByTestId(vegaWallet)
.first()
.within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'0.9999'
);
});
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
cy.contains('Vote breakdown').should('be.visible', {
timeout: 10000,
});
cy.get(voteButtons).should('not.exist');
cy.getByTestId(voteButtons).should('not.exist');
cy.getByTestId('min-proposal-requirements').should(
'have.text',
`You must have at least ${this.minVoterBalance} VEGA associated to vote on this proposal`
@@ -311,20 +313,20 @@ context(
cy.get('[data-testid="disconnect"]').click();
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() =>
cy.get(viewProposalButton).click()
cy.getByTestId(viewProposalButton).click()
);
});
// 3001-VOTE-075
// 3001-VOTE-076
cy.get(connectToVegaWalletButton)
cy.getByTestId(connectToVegaWalletButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet')
.click();
cy.getByTestId('connector-jsonRpc').click();
cy.get(vegaWalletNameElement).should('be.visible');
cy.get(connectToVegaWalletButton).should('not.exist');
cy.getByTestId(vegaWalletNameElement).should('be.visible');
cy.getByTestId(connectToVegaWalletButton).should('not.exist');
// 3001-VOTE-100
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).contains(
'1.00',
txTimeout
);
@@ -31,27 +31,25 @@ import {
} from '../../support/wallet-functions';
const proposalListItem = '[data-testid="proposals-list-item"]';
const openProposals = '[data-testid="open-proposals"]';
const proposalType = '[data-testid="proposal-type"]';
const proposalDetails = '[data-testid="proposal-details"]';
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
const newProposalTitle = '[data-testid="proposal-title"]';
const newProposalDescription = '[data-testid="proposal-description"]';
const newProposalTerms = '[data-testid="proposal-terms"]';
const newProposedParameterValue =
'[data-testid="selected-proposal-param-new-value"]';
const minVoteDeadline = '[data-testid="min-vote"]';
const maxVoteDeadline = '[data-testid="max-vote"]';
const minValidationDeadline = '[data-testid="min-validation"]';
const minEnactDeadline = '[data-testid="min-enactment"]';
const maxEnactDeadline = '[data-testid="max-enactment"]';
const inputError = '[data-testid="input-error-text"]';
const enactmentDeadlineError =
'[data-testid="enactment-before-voting-deadline"]';
const proposalDownloadBtn = '[data-testid="proposal-download-json"]';
const openProposals = 'open-proposals';
const proposalType = 'proposal-type';
const proposalDetails = 'proposal-details';
const newProposalSubmitButton = 'proposal-submit';
const proposalVoteDeadline = 'proposal-vote-deadline';
const proposalParameterSelect = 'proposal-parameter-select';
const proposalMarketSelect = 'proposal-market-select';
const newProposalTitle = 'proposal-title';
const newProposalDescription = 'proposal-description';
const newProposalTerms = 'proposal-terms';
const newProposedParameterValue = 'selected-proposal-param-new-value';
const minVoteDeadline = 'min-vote';
const maxVoteDeadline = 'max-vote';
const minValidationDeadline = 'min-validation';
const minEnactDeadline = 'min-enactment';
const maxEnactDeadline = 'max-enactment';
const inputError = 'input-error-text';
const enactmentDeadlineError = 'enactment-before-voting-deadline';
const proposalDownloadBtn = 'proposal-download-json';
const feedbackError = '[data-testid="Error"]';
const viewProposalBtn = 'view-proposal-btn';
const liquidityVoteStatus = 'liquidity-votes-status';
@@ -88,18 +86,20 @@ context(
it('Unable to submit network parameter with missing/invalid fields', function () {
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(proposalDownloadBtn).click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type(
cy.getByTestId(proposalDownloadBtn).click();
cy.getByTestId(inputError).should('have.length', 3);
cy.getByTestId(newProposalTitle).type(
'Invalid update network parameter proposal'
);
cy.get(newProposalDescription).type('E2E invalid test for proposals');
cy.get(proposalParameterSelect).select(
cy.getByTestId(newProposalDescription).type(
'E2E invalid test for proposals'
);
cy.getByTestId(proposalParameterSelect).select(
'spam_protection_proposal_min_tokens'
);
cy.get(newProposedParameterValue).type('0');
cy.get(proposalVoteDeadline).clear().type('0');
cy.get(proposalDownloadBtn)
cy.getByTestId(newProposedParameterValue).type('0');
cy.getByTestId(proposalVoteDeadline).clear().type('0');
cy.getByTestId(proposalDownloadBtn)
.click()
.then(() => {
cy.wrap(
@@ -109,7 +109,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
});
});
cy.get(newProposalSubmitButton).click();
cy.getByTestId(newProposalSubmitButton).click();
validateDialogContentMsg('PROPOSAL_ERROR_CLOSE_TIME_TOO_SOON');
});
@@ -117,29 +117,33 @@ context(
it('Able to download and submit network param proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
// 3007-PNEC-006
cy.get(newProposalTitle)
cy.getByTestId(newProposalTitle)
.siblings()
.should('contain.text', '(100 characters or less)');
// 3007-PNEC-004 3007-PNEC-005
cy.get(newProposalTitle).type('Test update network parameter proposal');
cy.getByTestId(newProposalTitle).type(
'Test update network parameter proposal'
);
// 3007-PNEC-009
cy.get(newProposalDescription)
cy.getByTestId(newProposalDescription)
.siblings()
.should('contain.text', '(20,000 characters or less)');
// 3007-PNEC-007 3007-PNEC-008
cy.get(newProposalDescription).type('E2E test for downloading proposals');
cy.getByTestId(newProposalDescription).type(
'E2E test for downloading proposals'
);
// 3007-PNEC-010
cy.get(proposalParameterSelect).select(
cy.getByTestId(proposalParameterSelect).select(
'governance_proposal_asset_minClose'
);
// 3007-PNEC-011
cy.get(newProposedParameterValue).type('10s');
cy.getByTestId(newProposedParameterValue).type('10s');
// 3007-PNEC-012
cy.get(proposalVoteDeadline).clear().type('2');
cy.getByTestId(proposalVoteDeadline).clear().type('2');
// 3007-PNEC-013 3007-PNEC-014
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
// 3007-PNEC-015
cy.get(maxEnactDeadline).click();
cy.getByTestId(maxEnactDeadline).click();
// 3007-PNEC-016
cy.getByTestId('enactment-date').invoke('text').should('not.be.empty');
// 3007-PNEC-017
@@ -148,7 +152,7 @@ context(
).should('be.visible');
// 3007-PNE-018
cy.log('Download updated proposal file');
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -178,19 +182,21 @@ context(
it('Unable to submit network parameter proposal with vote deadline above enactment deadline', function () {
navigateTo(navigation.proposals);
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(newProposalTitle).type('Test update network parameter proposal');
cy.get(newProposalDescription).type('invalid deadlines');
cy.get(proposalParameterSelect).select(
cy.getByTestId(newProposalTitle).type(
'Test update network parameter proposal'
);
cy.getByTestId(newProposalDescription).type('invalid deadlines');
cy.getByTestId(proposalParameterSelect).select(
'spam_protection_proposal_min_tokens'
);
cy.get(newProposedParameterValue).type('0');
cy.get(proposalVoteDeadline).clear().type('0');
cy.get(maxVoteDeadline).click();
cy.get(enactmentDeadlineError).should(
cy.getByTestId(newProposedParameterValue).type('0');
cy.getByTestId(proposalVoteDeadline).clear().type('0');
cy.getByTestId(maxVoteDeadline).click();
cy.getByTestId(enactmentDeadlineError).should(
'have.text',
'The proposal will fail if enactment is earlier than the voting deadline'
);
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -201,7 +207,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
});
});
cy.get(newProposalSubmitButton).click();
cy.getByTestId(newProposalSubmitButton).click();
validateFeedBackMsg(
'Invalid params: proposal_submission.terms.closing_timestamp (cannot be after enactment time)'
);
@@ -214,16 +220,16 @@ context(
function () {
const proposalTitle = 'Test new market proposal';
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalTitle).type('Test new market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(newProposalTitle).type('Test new market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
const newMarketPayload = JSON.stringify(newMarketProposal);
cy.get(newProposalTerms).type(newMarketPayload, {
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -259,19 +265,19 @@ context(
'Invalid params: the transaction does not use a valid Vega command: unknown field "invalid" in vega.NewMarket';
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.get(proposalDownloadBtn).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type('Test new market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3);
cy.getByTestId(newProposalTitle).type('Test new market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
newMarketProposal.invalid = 'I am an invalid field';
const newMarketPayload = JSON.stringify(newMarketProposal);
cy.get(newProposalTerms).type(newMarketPayload, {
cy.getByTestId(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -282,7 +288,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
validateFeedBackMsg(errorMsg);
});
@@ -293,17 +299,19 @@ context(
switchVegaWalletPubKey();
stakingPageAssociateTokens('1');
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal - rejected');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
cy.getByTestId(newProposalTitle).type(
'Test update market proposal - rejected'
);
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -314,7 +322,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
validateDialogContentMsg('PROPOSAL_ERROR_INSUFFICIENT_EQUITY_LIKE_SHARE');
closeDialog();
@@ -332,17 +340,19 @@ context(
vegaWalletPublicKey
);
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal - rejected');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
cy.getByTestId(newProposalTitle).type(
'Test update market proposal - rejected'
);
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1');
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -353,7 +363,7 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false });
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
validateFeedBackMsg(
'Network error: the network blocked the transaction through the spam protection: party has insufficient associated governance tokens in their staking account to submit proposal request (ABCI code 89)'
@@ -368,9 +378,9 @@ context(
vegaWalletPublicKey
);
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select('Test market 1');
cy.getByTestId(newProposalTitle).type('Test update market proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(proposalMarketSelect).select('Test market 1');
cy.get('[data-testid="update-market-details"]').within(() => {
cy.get('dd').eq(0).should('have.text', 'Test market 1');
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
@@ -385,12 +395,12 @@ context(
});
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
const newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
cy.getByTestId(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -437,19 +447,19 @@ context(
it('Able to submit new asset proposal using min deadlines', function () {
const proposalTitle = 'Test new asset proposal';
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalTitle).type(proposalTitle);
cy.get(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(newProposalTitle).type(proposalTitle);
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
const newAssetPayload = JSON.stringify(newAssetProposal);
cy.get(newProposalTerms).type(newAssetPayload, {
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(minVoteDeadline).click();
cy.get(minValidationDeadline).click();
cy.get(minEnactDeadline).click();
cy.get(proposalDownloadBtn)
cy.getByTestId(minVoteDeadline).click();
cy.getByTestId(minValidationDeadline).click();
cy.getByTestId(minEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -460,9 +470,9 @@ context(
submitUniqueRawProposal({ proposalBody: filePath, submit: false }); // 3005-PASN-003
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
closeDialog();
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.getByTestId(newProposalSubmitButton).should('be.visible').click();
// cannot submit a proposal with ERC20 address already in use
cy.contains('Proposal rejected', proposalTimeout).should('be.visible');
validateDialogContentMsg('PROPOSAL_ERROR_ERC20_ADDRESS_ALREADY_IN_USE');
@@ -483,8 +493,8 @@ context(
it('Unable to submit new asset proposal with missing/invalid fields', function () {
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.get(proposalDownloadBtn).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3);
});
it('Able to submit update asset proposal using min deadline', function () {
@@ -493,9 +503,9 @@ context(
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails();
cy.get(minVoteDeadline).click();
cy.get(minEnactDeadline).click();
cy.get(proposalDownloadBtn)
cy.getByTestId(minVoteDeadline).click();
cy.getByTestId(minEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -507,13 +517,16 @@ context(
});
});
navigateTo(navigation.proposals);
cy.get(openProposals).within(() => {
cy.get(proposalType)
cy.getByTestId(openProposals).within(() => {
cy.getByTestId(proposalType)
.contains('Update asset')
.parentsUntil(proposalListItem)
.last()
.within(() => {
cy.get(proposalDetails).should('contain.text', assetId.slice(0, 6)); // 3001-VOTE-029
cy.getByTestId(proposalDetails).should(
'contain.text',
assetId.slice(0, 6)
); // 3001-VOTE-029
cy.getByTestId(viewProposalBtn).click();
});
});
@@ -533,9 +546,9 @@ context(
it('Able to submit update asset proposal using max deadline', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
enterUpdateAssetProposalDetails();
cy.get(maxVoteDeadline).click();
cy.get(maxEnactDeadline).click();
cy.get(proposalDownloadBtn)
cy.getByTestId(maxVoteDeadline).click();
cy.getByTestId(maxEnactDeadline).click();
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -550,36 +563,36 @@ context(
it('Unable to submit edit asset proposal with missing/invalid fields', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
cy.get(proposalDownloadBtn).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.getByTestId(proposalDownloadBtn).should('be.visible').click();
cy.getByTestId(inputError).should('have.length', 3);
});
it('Able to download and submit freeform proposal', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM);
// 3008-PFRO-006
cy.get(newProposalTitle)
cy.getByTestId(newProposalTitle)
.siblings()
.should('contain.text', '(100 characters or less)'); // 3008-PFRO-007
// 3008-PFRO-005
cy.get(newProposalTitle).type('Test freeform proposal form');
cy.getByTestId(newProposalTitle).type('Test freeform proposal form');
// 3008-PFRO-009
cy.get(newProposalDescription)
cy.getByTestId(newProposalDescription)
.siblings()
.should('contain.text', '(20,000 characters or less)'); // 3008-PFRO-010
// 3008-PFRO-008 3002-PROP-012 3002-PROP-016
cy.get(newProposalDescription).type(
cy.getByTestId(newProposalDescription).type(
'E2E test for downloading freeform proposal'
);
// 3008-PFRO-012
cy.get(minVoteDeadline).should('exist'); // 3002-PROP-008
cy.get(maxVoteDeadline).should('exist');
cy.getByTestId(minVoteDeadline).should('exist'); // 3002-PROP-008
cy.getByTestId(maxVoteDeadline).should('exist');
// 3008-PFRO-011
cy.get(proposalVoteDeadline).clear().type('2');
cy.getByTestId(proposalVoteDeadline).clear().type('2');
// 3008-PFRO-013 3008-PFRO-014
cy.getByTestId('voting-date').invoke('text').should('not.be.empty');
// 3008-PFRO-015
cy.log('Download updated proposal file');
cy.get(proposalDownloadBtn)
cy.getByTestId(proposalDownloadBtn)
.should('be.visible')
.click()
.then(() => {
@@ -613,11 +626,11 @@ context(
}
function enterUpdateAssetProposalDetails() {
cy.get(newProposalTitle).type('Test update asset proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.getByTestId(newProposalTitle).type('Test update asset proposal');
cy.getByTestId(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/update-asset').then((newAssetProposal) => {
const newAssetPayload = JSON.stringify(newAssetProposal);
cy.get(newProposalTerms).type(newAssetPayload, {
cy.getByTestId(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
@@ -24,12 +24,12 @@ import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { vegaWalletSetSpecifiedApprovalAmount } from '../../support/wallet-functions';
const proposalListItem = 'proposals-list-item';
const openProposals = '[data-testid="open-proposals"]';
const openProposals = 'open-proposals';
const voteStatus = 'vote-status';
const proposalType = 'proposal-type';
const proposalStatus = 'proposal-status';
const proposalClosingDate = '[data-testid="vote-details"]';
const viewProposalButton = '[data-testid="view-proposal-btn"]';
const proposalClosingDate = 'vote-details';
const viewProposalButton = 'view-proposal-btn';
const voteBreakDownToggle = 'vote-breakdown-toggle';
describe('Governance flow for proposal list', { tags: '@slow' }, function () {
@@ -62,13 +62,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
}
navigateTo(navigation.proposals);
cy.get(openProposals).within(() => {
cy.get(proposalClosingDate)
cy.getByTestId(openProposals).within(() => {
cy.getByTestId(proposalClosingDate)
.first()
.invoke('text')
.should('match', /days|minutes/);
cy.get(proposalClosingDate).should('contain.text', 'months');
cy.get(proposalClosingDate).last().should('contain.text', 'year');
cy.getByTestId(proposalClosingDate).should('contain.text', 'months');
cy.getByTestId(proposalClosingDate).last().should('contain.text', 'year');
});
});
@@ -77,7 +77,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
const proposalTitle = generateFreeFormProposalTitle();
submitUniqueRawProposal({ proposalTitle: proposalTitle });
cy.get('[data-testid="set-proposals-filter-visible"]').click();
cy.get('[data-testid="proposal-filter-toggle"]').click();
cy.get('[data-testid="filter-input"]').type(proposerId);
// cy.get(`#${proposalId}`).should('contain', proposalId);
cy.contains(proposalTitle).should('be.visible');
@@ -106,7 +106,7 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
createRawProposal(this.minProposerBalance);
cy.get<testFreeformProposal>('@rawProposal').then((rawProposal) => {
getProposalFromTitle(rawProposal.rationale.title).within(() => {
cy.get(viewProposalButton).should('be.visible');
cy.getByTestId(viewProposalButton).should('be.visible');
cy.getByTestId(proposalType).should('have.text', 'Freeform');
cy.getByTestId(proposalStatus).should('have.text', 'Open');
});
@@ -124,13 +124,13 @@ describe('Governance flow for proposal list', { tags: '@slow' }, function () {
'have.text',
'Participation not reached'
);
cy.get(viewProposalButton).click();
cy.getByTestId(viewProposalButton).click();
});
voteForProposal('for');
navigateTo(navigation.proposals);
getProposalFromTitle(proposalTitle).within(() => {
cy.getByTestId(voteStatus).should('have.text', 'Set to pass');
cy.get(viewProposalButton).click();
cy.getByTestId(viewProposalButton).click();
});
cy.getByTestId(voteBreakDownToggle).click();
getProposalInformationFromTable('Token participation met')
@@ -17,8 +17,7 @@ import {
} from '../../support/wallet-functions';
const vegaAssetAddress = '0x67175Da1D5e966e40D11c4B2519392B2058373de';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
const rewardsTable = 'epoch-total-rewards-table';
const txTimeout = Cypress.env('txTimeout');
const rewardsTimeOut = { timeout: 60000 };
@@ -40,7 +39,7 @@ context('rewards - flow', { tags: '@slow' }, function () {
cy.associateTokensToVegaWallet('6000');
navigateTo(navigation.validators);
cy.VegaWalletTopUpRewardsPool();
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
'6,000.0',
txTimeout
@@ -4,7 +4,6 @@ import {
verifyStakedBalance,
verifyEthWalletTotalAssociatedBalance,
verifyEthWalletAssociatedBalance,
waitForSpinner,
navigateTo,
navigation,
turnTelemetryOff,
@@ -58,6 +57,7 @@ context(
before('visit staking tab and connect vega wallet', function () {
cy.visit('/');
ethereumWalletConnect();
cy.connectVegaWallet();
vegaWalletSetSpecifiedApprovalAmount('1000');
});
@@ -67,10 +67,9 @@ context(
function () {
cy.clearLocalStorage();
turnTelemetryOff();
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
ethereumWalletConnect();
// Go to homepage to allow wallet teardown without epoch timer refreshing page
navigateTo(navigation.home);
vegaWalletTeardown();
navigateTo(navigation.validators);
}
);
@@ -128,6 +127,7 @@ context(
cy.getByTestId('staked-by-user-tooltip')
.first()
.should('have.text', 'Staked by me: 2.00');
waitForBeginningOfEpoch();
cy.getByTestId('total-pending-stake').first().realHover();
cy.getByTestId('pending-user-stake-tooltip')
.first()
@@ -398,6 +398,7 @@ context(
vegaWalletSetSpecifiedApprovalAmount('1000');
cy.reload();
ethereumWalletConnect();
cy.connectVegaWallet();
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
cy.get('button').contains('Select a validator to nominate').click();
@@ -503,11 +504,6 @@ context(
);
});
afterEach('Teardown Wallet', function () {
navigateTo(navigation.home);
vegaWalletTeardown();
});
function verifyNextEpochValue(amount: number) {
cy.getByTestId('stake-next-epoch', epochTimeout)
.contains(amount, epochTimeout)
@@ -21,25 +21,24 @@ import {
vegaWalletTeardown,
} from '../../support/wallet-functions';
const ethWalletContainer = '[data-testid="ethereum-wallet"]';
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const txTimeout = Cypress.env('txTimeout');
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const ethWalletContainer = 'ethereum-wallet';
const vegaWalletAssociatedBalance = 'currency-value';
const vegaWalletUnstakedBalance = 'vega-wallet-balance-unstaked';
const ethWalletAssociateButton = '[data-testid="associate-btn"]:visible';
const associateWalletRadioButton = '[data-testid="associate-radio-wallet"]';
const tokenAmountInputBox = '[data-testid="token-amount-input"]';
const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const associateWalletRadioButton = 'associate-radio-wallet';
const tokenAmountInputBox = 'token-amount-input';
const tokenSubmitButton = 'token-input-submit-button';
const ethWalletDissociateButton = '[href="/token/disassociate"]:visible';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
const associatedKey = '[data-testid="associated-key"]';
const associatedAmount = '[data-testid="associated-amount"]';
const associateCompleteText = '[data-testid="transaction-complete-body"]';
const disassociationWarning = '[data-testid="disassociation-warning"]';
const vestingContractSection = 'vega-in-vesting-contract';
const vegaInWalletSection = 'vega-in-wallet';
const connectedVegaKey = 'connected-vega-key';
const associatedKey = 'associated-key';
const associatedAmount = 'associated-amount';
const associateCompleteText = 'transaction-complete-body';
const disassociationWarning = 'disassociation-warning';
const vegaWallet = 'aside [data-testid="vega-wallet"]';
const vegaWalletPublicKeyShort = Cypress.env('vegaWalletPublicKeyShort');
const txTimeout = Cypress.env('txTimeout');
context(
'Token association flow - with eth and vega wallets connected',
@@ -89,12 +88,15 @@ context(
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
2.0
);
}
);
@@ -127,7 +129,7 @@ context(
verifyEthWalletAssociatedBalance('1,001.00');
verifyEthWalletTotalAssociatedBalance('7,001.00');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should(
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
'1,001.00'
);
@@ -137,14 +139,20 @@ context(
it('Able to disassociate a partial amount of tokens currently associated', function () {
stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible');
stakingPageDisassociateTokens('1');
verifyEthWalletAssociatedBalance('1.0');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 1.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
1.0
);
});
});
@@ -154,21 +162,24 @@ context(
'Warning: Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.';
stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible');
cy.get(ethWalletDissociateButton).click();
cy.get(disassociationWarning).should('contain', warningText);
cy.getByTestId(disassociationWarning).should('contain', warningText);
stakingPageDisassociateAllTokens();
cy.get(ethWalletContainer)
cy.getByTestId(ethWalletContainer)
.first()
.within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
'not.exist'
);
});
cy.get(ethWalletContainer)
cy.getByTestId(ethWalletContainer)
.first()
.within(() => {
cy.contains(vegaWalletPublicKeyShort, { timeout: 20000 }).should(
@@ -176,7 +187,10 @@ context(
);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 0.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
0.0
);
});
});
@@ -198,9 +212,15 @@ context(
verifyEthWalletAssociatedBalance('2.0');
verifyEthWalletTotalAssociatedBalance('2.0');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
2.0
);
stakingPageDisassociateTokens('1', {
type: 'contract',
skipConfirmation: true,
@@ -221,45 +241,54 @@ context(
cy.get('button').contains('Select a validator to nominate').click();
cy.getByTestId('epoch-countdown').should('be.visible');
stakingPageAssociateTokens('37', { type: 'contract' });
cy.get(vestingContractSection)
cy.getByTestId(vestingContractSection)
.first()
.within(() => {
cy.get(associatedKey).should(
cy.getByTestId(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 37);
cy.getByTestId(associatedAmount, txTimeout).should('contain', 37);
});
cy.get(vegaInWalletSection)
cy.getByTestId(vegaInWalletSection)
.first()
.within(() => {
cy.get(associatedKey).should(
cy.getByTestId(associatedKey).should(
'contain',
Cypress.env('vegaWalletPublicKeyShort')
);
cy.get(associatedAmount, txTimeout).should('contain', 21);
cy.getByTestId(associatedAmount, txTimeout).should('contain', 21);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 58);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
58
);
});
stakingPageDisassociateTokens('6', { type: 'contract' });
cy.get(vestingContractSection)
cy.getByTestId(vestingContractSection)
.first()
.within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 31);
cy.getByTestId(associatedAmount, txTimeout).should('contain', 31);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 52);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
52
);
});
navigateTo(navigation.validators);
stakingPageDisassociateTokens('9', { type: 'wallet' });
cy.get(vegaInWalletSection)
cy.getByTestId(vegaInWalletSection)
.first()
.within(() => {
cy.get(associatedAmount, txTimeout).should('contain', 12);
cy.getByTestId(associatedAmount, txTimeout).should('contain', 12);
});
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 43);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
43
);
});
});
@@ -268,10 +297,10 @@ context(
// 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).click();
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.get(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
cy.getByTestId(associateWalletRadioButton, { timeout: 30000 }).click();
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.getByTestId(tokenAmountInputBox, { timeout: 10000 }).type('6500000');
cy.getByTestId(tokenSubmitButton, txTimeout).should('be.disabled');
});
// 1004-ASSO-004
@@ -296,22 +325,25 @@ context(
it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).click();
cy.get(associateWalletRadioButton).click();
cy.get(connectedVegaKey).should(
cy.getByTestId(associateWalletRadioButton).click();
cy.getByTestId(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey')
);
switchVegaWalletPubKey();
cy.get(connectedVegaKey).should(
cy.getByTestId(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey2')
);
stakingPageAssociateTokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
cy.getByTestId(vegaWalletAssociatedBalance, txTimeout).should(
'contain',
2.0
);
});
cy.get(associateCompleteText).should(
cy.getByTestId(associateCompleteText).should(
'have.text',
`Vega key ${Cypress.env(
'vegaWalletPublicKey2Short'
@@ -10,9 +10,10 @@ import {
} from '../../support/governance.functions';
import { mockNetworkUpgradeProposal } from '../../support/proposal.functions';
const proposalDocumentationLink = '[data-testid="proposal-documentation-link"]';
const proposalDocsLink = 'proposal-docs-link';
const proposalDocumentationLink = 'proposal-documentation-link';
const connectToVegaWalletButton = 'connect-to-vega-wallet-btn';
const governanceDocsUrl = 'https://vega.xyz/governance';
const connectToVegaWalletButton = '[data-testid="connect-to-vega-wallet-btn"]';
context(
'Governance Page - verify elements on page',
@@ -41,7 +42,7 @@ context(
it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001
cy.get(proposalDocumentationLink)
cy.getByTestId(proposalDocumentationLink)
.should('be.visible')
.and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href')
@@ -64,7 +65,7 @@ context(
// 3007-PNE-021
it('should have documentation links for network parameter proposal', function () {
goToMakeNewProposal(governanceProposalType.NETWORK_PARAMETER);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/network-parameter-proposal');
@@ -73,7 +74,7 @@ context(
// 3003-PMAN-002 3003-PMAN-005
it('should have documentation links for new market proposal', function () {
goToMakeNewProposal(governanceProposalType.NEW_MARKET);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/new-market-proposal');
@@ -82,7 +83,7 @@ context(
// 3004-PMAC-005
it('should have documentation links for update market proposal', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_MARKET);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/update-market-proposal');
@@ -91,7 +92,7 @@ context(
// 3005-PASN-002 005-PASN-005
it('should have documentation links for new asset proposal', function () {
goToMakeNewProposal(governanceProposalType.NEW_ASSET);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/new-asset-proposal');
@@ -100,7 +101,7 @@ context(
// 3006-PASC-002 3006-PASC-005
it('should have documentation links for update asset proposal', function () {
goToMakeNewProposal(governanceProposalType.UPDATE_ASSET);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/update-asset-proposal');
@@ -109,7 +110,7 @@ context(
// 3008-PFRO-003 3008-PFRO-017
it('should have documentation links for freeform proposal', function () {
goToMakeNewProposal(governanceProposalType.FREEFORM);
cy.getByTestId('proposal-docs-link')
cy.getByTestId(proposalDocsLink)
.find('a')
.should('have.attr', 'href')
.and('contain', '/tutorials/proposals/freeform-proposal');
@@ -117,7 +118,7 @@ context(
it('should be able to see a connect wallet button - if vega wallet disconnected and user is submitting new proposal', function () {
goToMakeNewProposal(governanceProposalType.RAW);
cy.get(connectToVegaWalletButton)
cy.getByTestId(connectToVegaWalletButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
});
@@ -165,6 +166,7 @@ context(
);
});
});
cy.get('[data-testid="closed-proposals-toggle-networkUpgrades"]').click();
cy.getByTestId('closed-proposals').within(() => {
cy.getByTestId('protocol-upgrade-proposals-list-item').should(
'have.length',
@@ -5,8 +5,8 @@ import {
} from '../../support/common.functions';
import { waitForBeginningOfEpoch } from '../../support/staking.functions';
const viewToggle = '[data-testid="epoch-reward-view-toggle-total"]';
const warning = '[data-testid="callout"]';
const viewToggle = 'epoch-reward-view-toggle-total';
const warning = 'callout';
context(
'Rewards Page - verify elements on page',
@@ -27,7 +27,7 @@ context(
});
it('should have epoch warning', function () {
cy.get(warning)
cy.getByTestId(warning)
.should('be.visible')
.and(
'have.text',
@@ -36,7 +36,7 @@ context(
});
it('should have toggle for seeing total vs individual rewards', function () {
cy.get(viewToggle).should('be.visible');
cy.getByTestId(viewToggle).should('be.visible');
});
// Skipping due to bug #3471 causing flaky failuress
@@ -1,18 +1,17 @@
import { navigateTo, navigation } from '../../support/common.functions';
const tokenDetailsTable = '.token-details';
const address = '[data-testid="token-address"]';
const contract = '[data-testid="token-contract"]';
const totalSupply = '[data-testid="total-supply"]';
const circulatingSupply = '[data-testid="circulating-supply"]';
const staked = '[data-testid="staked"]';
const tranchesLink = '[data-testid="tranches-link"]';
const redeemBtn = '[data-testid="check-vesting-page-btn"]';
const getVegaWalletLink = '[data-testid="get-vega-wallet-link"]';
const associateVegaLink =
'[data-testid="associate-vega-tokens-link-on-homepage"]';
const stakingBtn = '[data-testid="staking-button-on-homepage"]';
const governanceBtn = '[data-testid="governance-button-on-homepage"]';
const address = 'token-address';
const contract = 'token-contract';
const totalSupply = 'total-supply';
const circulatingSupply = 'circulating-supply';
const staked = 'staked';
const tranchesLink = 'tranches-link';
const redeemBtn = 'check-vesting-page-btn';
const getVegaWalletLink = 'get-vega-wallet-link';
const associateVegaLink = 'associate-vega-tokens-link-on-homepage';
const stakingBtn = 'staking-button-on-homepage';
const governanceBtn = 'governance-button-on-homepage';
const vegaTokenAddress = Cypress.env('vegaTokenAddress');
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
@@ -25,7 +24,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
describe('THE $VEGA TOKEN table', function () {
it('should have TOKEN ADDRESS', function () {
cy.get(tokenDetailsTable).within(() => {
cy.get(address)
cy.getByTestId(address)
.should('be.visible')
.invoke('text')
.should('be.equal', vegaTokenAddress);
@@ -34,7 +33,7 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
it('should have VESTING CONTRACT', function () {
// 1004-ASSO-001
cy.get(tokenDetailsTable).within(() => {
cy.get(contract)
cy.getByTestId(contract)
.should('be.visible')
.invoke('text')
.should('be.equal', vegaTokenContractAddress);
@@ -42,56 +41,56 @@ context('Verify elements on Token page', { tags: '@smoke' }, function () {
});
it('should have TOTAL SUPPLY', function () {
cy.get(tokenDetailsTable).within(() => {
cy.get(totalSupply).should('be.visible');
cy.getByTestId(totalSupply).should('be.visible');
});
});
it('should have CIRCULATING SUPPLY', function () {
cy.get(tokenDetailsTable).within(() => {
cy.get(circulatingSupply).should('be.visible');
cy.getByTestId(circulatingSupply).should('be.visible');
});
});
it('should have STAKED $VEGA', function () {
cy.get(tokenDetailsTable).within(() => {
cy.get(staked).should('be.visible');
cy.getByTestId(staked).should('be.visible');
});
});
});
describe('links and buttons', function () {
it('should have TRANCHES link', function () {
cy.get(tranchesLink)
cy.getByTestId(tranchesLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', '/token/tranches');
});
it('should have REDEEM button', function () {
cy.get(redeemBtn)
cy.getByTestId(redeemBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
.and('equal', '/token/redeem');
});
it('should have GET VEGA WALLET link', function () {
cy.get(getVegaWalletLink)
cy.getByTestId(getVegaWalletLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', 'https://vega.xyz/wallet');
});
it('should have ASSOCIATE VEGA TOKENS link', function () {
cy.get(associateVegaLink)
cy.getByTestId(associateVegaLink)
.should('be.visible')
.and('have.attr', 'href')
.and('equal', '/token/associate');
});
it('should have STAKING button', function () {
cy.get(stakingBtn)
cy.getByTestId(stakingBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
.and('equal', '/validators');
});
it('should have GOVERNANCE button', function () {
cy.get(governanceBtn)
cy.getByTestId(governanceBtn)
.should('be.visible')
.parent()
.should('have.attr', 'href')
@@ -12,28 +12,26 @@ import {
} from '../../support/staking.functions';
import { previousEpochData } from '../../fixtures/mocks/previous-epoch';
const guideLink = '[data-testid="staking-guide-link"]';
const validatorTitle = '[data-testid="validator-node-title"]';
const validatorId = '[data-testid="validator-id"]';
const validatorPubKey = '[data-testid="validator-public-key"]';
const ethAddressLink = '[data-testid="link"]';
const validatorStatus = '[data-testid="validator-status"]';
const totalStake = '[data-testid="total-stake"]';
const pendingStake = '[data-testid="pending-stake"]';
const stakedByOperator = '[data-testid="staked-by-operator"]';
const stakedByDelegates = '[data-testid="staked-by-delegates"]';
const stakeShare = '[data-testid="stake-percentage"]';
const stakedByOperatorToolTip = '[data-testid="staked-operator-tooltip"]';
const stakedByDelegatesToolTip = '[data-testid="staked-delegates-tooltip"]';
const totalStakedToolTip = '[data-testid="total-staked-tooltip"]';
const unnormalisedVotingPowerToolTip =
'[data-testid="unnormalised-voting-power-tooltip"]';
const normalisedVotingPowerToolTip =
'[data-testid="normalised-voting-power-tooltip"]';
const performancePenaltyToolTip = '[data-testid="performance-penalty-tooltip"]';
const overstakedPenaltyToolTip = '[data-testid="overstaked-penalty-tooltip"]';
const multisigPenaltyToolTip = '[data-testid="multisig-error-tooltip"]';
const epochCountDown = '[data-testid="epoch-countdown"]';
const guideLink = 'staking-guide-link';
const validatorTitle = 'validator-node-title';
const validatorId = 'validator-id';
const validatorPubKey = 'validator-public-key';
const ethAddressLink = 'link';
const validatorStatus = 'validator-status';
const totalStake = 'total-stake';
const pendingStake = 'pending-stake';
const stakedByOperator = 'staked-by-operator';
const stakedByDelegates = 'staked-by-delegates';
const stakeShare = 'stake-percentage';
const stakedByOperatorToolTip = 'staked-operator-tooltip';
const stakedByDelegatesToolTip = 'staked-delegates-tooltip';
const totalStakedToolTip = 'total-staked-tooltip';
const unnormalisedVotingPowerToolTip = 'unnormalised-voting-power-tooltip';
const normalisedVotingPowerToolTip = 'normalised-voting-power-tooltip';
const performancePenaltyToolTip = 'performance-penalty-tooltip';
const overstakedPenaltyToolTip = 'overstaked-penalty-tooltip';
const multisigPenaltyToolTip = 'multisig-error-tooltip';
const epochCountDown = 'epoch-countdown';
const stakeNumberRegex = /^\d{1,3}(,\d{3})*(\.\d+)?$/;
context('Validators Page - verify elements on page', function () {
@@ -52,7 +50,7 @@ context('Validators Page - verify elements on page', function () {
it('Should have Staking Guide link visible', function () {
// 1002-STKE-003
cy.get(guideLink)
cy.getByTestId(guideLink)
.should('be.visible')
.and('have.text', 'Read more about staking on Vega')
.and(
@@ -95,13 +93,13 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('total-stake').first().realHover();
cy.get(stakedByOperatorToolTip)
cy.getByTestId(stakedByOperatorToolTip)
.invoke('text')
.should('contain', 'Staked by operator: 3,000.00');
cy.get(stakedByDelegatesToolTip)
cy.getByTestId(stakedByDelegatesToolTip)
.invoke('text')
.should('contain', 'Staked by delegates: 0.00');
cy.get(totalStakedToolTip)
cy.getByTestId(totalStakedToolTip)
.invoke('text')
.should('contain', 'Total stake: 3,000.00');
});
@@ -118,10 +116,10 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('normalised-voting-power').first().realHover();
cy.get(unnormalisedVotingPowerToolTip)
cy.getByTestId(unnormalisedVotingPowerToolTip)
.invoke('text')
.should('contain', 'Unnormalised voting power: 20.00%');
cy.get(normalisedVotingPowerToolTip)
cy.getByTestId(normalisedVotingPowerToolTip)
.invoke('text')
.should('contain', 'Normalised voting power: 50.00%');
});
@@ -139,10 +137,10 @@ context('Validators Page - verify elements on page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('total-penalty').realHover();
cy.get(performancePenaltyToolTip)
cy.getByTestId(performancePenaltyToolTip)
.invoke('text')
.should('contain', 'Performance penalty: 0.00%');
cy.get(overstakedPenaltyToolTip)
cy.getByTestId(overstakedPenaltyToolTip)
.invoke('text')
.should('contain', 'Overstaked penalty: 60.00%'); // value not asserted due to #2886
});
@@ -161,12 +159,12 @@ context('Validators Page - verify elements on page', function () {
});
waitForBeginningOfEpoch();
cy.getByTestId('total-penalty').first().realHover();
cy.get(multisigPenaltyToolTip)
cy.getByTestId(multisigPenaltyToolTip)
.invoke('text')
.should('contain', 'Multisig penalty: 100%');
cy.getByTestId('total-penalty').eq(1).realHover();
cy.get(multisigPenaltyToolTip)
cy.getByTestId(multisigPenaltyToolTip)
.invoke('text')
.should('contain', 'Multisig penalty: 100%');
});
@@ -185,53 +183,59 @@ context('Validators Page - verify elements on page', function () {
// 1002-STKE-006
it('Should be able to see validator name', function () {
cy.get(validatorTitle).should('not.be.empty');
cy.getByTestId(validatorTitle).should('not.be.empty');
});
// 1002-STKE-007
it('Should be able to see validator id', function () {
cy.get(validatorId).should('not.be.empty');
cy.getByTestId(validatorId).should('not.be.empty');
});
// 1002-STKE-008
it('Should be able to see validator public key', function () {
cy.get(validatorPubKey).should('not.be.empty');
cy.getByTestId(validatorPubKey).should('not.be.empty');
});
// 1002-STKE-010
it('Should be able to see Ethereum address', function () {
cy.get(ethAddressLink).should('not.be.empty').and('have.attr', 'href');
cy.getByTestId(ethAddressLink)
.should('not.be.empty')
.and('have.attr', 'href');
});
// TODO validators missing url for more information about them 1002-STKE-09
it('Should be able to see validator status', function () {
cy.get(validatorStatus).should('have.text', 'Consensus');
cy.getByTestId(validatorStatus).should('have.text', 'Consensus');
});
// 1002-STKE-012
it('Should be able to see total stake', function () {
cy.get(totalStake).invoke('text').should('match', stakeNumberRegex);
cy.getByTestId(totalStake)
.invoke('text')
.should('match', stakeNumberRegex);
});
it('Should be able to see pending stake', function () {
cy.get(pendingStake).invoke('text').should('match', stakeNumberRegex);
cy.getByTestId(pendingStake)
.invoke('text')
.should('match', stakeNumberRegex);
});
it('Should be able to see staked by operator', function () {
cy.get(stakedByOperator)
cy.getByTestId(stakedByOperator)
.invoke('text')
.should('match', stakeNumberRegex);
});
it('Should be able to see staked by delegates', function () {
cy.get(stakedByDelegates)
cy.getByTestId(stakedByDelegates)
.invoke('text')
.should('match', stakeNumberRegex);
});
// 1002-STKE-051
it('Should be able to see stake share in percentage', function () {
cy.get(stakeShare)
cy.getByTestId(stakeShare)
.invoke('text')
.then(($stakePercentage) => {
// The pattern must start at a word boundary (\b).
@@ -257,7 +261,7 @@ context('Validators Page - verify elements on page', function () {
const epochTitle = 'h3';
const nextEpochInfo = 'p';
cy.get(epochCountDown).within(() => {
cy.getByTestId(epochCountDown).within(() => {
cy.get(epochTitle).should('not.be.empty');
cy.get(nextEpochInfo).should('contain.text', 'Next epoch');
});
@@ -6,7 +6,7 @@ import {
} from '../../support/common.functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
const connectButton = '[data-testid="connect-to-eth-btn"]';
const connectButton = 'connect-to-eth-btn';
const lockedTokensInVestingContract = '6,499,972.30';
context(
@@ -29,7 +29,7 @@ context(
// 1005-VEST-018
it('should have connect Eth wallet button', function () {
cy.get(connectButton)
cy.getByTestId(connectButton)
.should('be.visible')
.and('have.text', 'Connect Ethereum wallet');
});
@@ -5,11 +5,11 @@ const walletContainer = 'aside [data-testid="ethereum-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1';
const connectToEthButton =
'[data-testid="connect-to-eth-wallet-button"]:visible';
const connectorList = '[data-testid="web3-connector-list"]';
const connectorList = 'web3-connector-list';
const associate = '[href="/token/associate"]';
const disassociate = '[href="/token/disassociate"]';
const disconnect = '[data-testid="disconnect-from-eth-wallet-button"]';
const accountNo = '[data-testid="ethereum-account-truncated"]';
const disconnect = 'disconnect-from-eth-wallet-button';
const accountNo = 'ethereum-account-truncated';
const currencyTitle = '[data-testid="currency-title"]:visible';
const currencyValue = '[data-testid="currency-value"]:visible';
const vegaInVesting = '[data-testid="vega-in-vesting-contract"]:visible';
@@ -18,8 +18,8 @@ const progressBar = '[data-testid="progress-bar"]:visible';
const currencyLocked = '[data-testid="currency-locked"]:visible';
const currencyUnlocked = '[data-testid="currency-unlocked"]:visible';
const dialog = '[role="dialog"]:visible';
const dialogHeader = '[data-testid="dialog-title"]';
const dialogCloseBtn = '[data-testid="dialog-close"]';
const dialogHeader = 'dialog-title';
const dialogCloseBtn = 'dialog-close';
context(
'Ethereum Wallet - verify elements on widget',
@@ -59,7 +59,7 @@ context(
it('should have Connect Ethereum header visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogHeader)
cy.getByTestId(dialogHeader)
.should('be.visible')
.and('have.text', 'Connect to your Ethereum wallet');
});
@@ -73,7 +73,7 @@ context(
'WalletConnect',
'WalletConnect Legacy',
];
cy.get(connectorList).within(() => {
cy.getByTestId(connectorList).within(() => {
cy.get('button').each(($btn, i) => {
cy.wrap($btn).should('be.visible').and('have.text', connectList[i]);
});
@@ -83,7 +83,7 @@ context(
after('close popup', function () {
cy.get(dialog)
.within(() => {
cy.get(dialogCloseBtn).click();
cy.getByTestId(dialogCloseBtn).click();
})
.should('not.exist');
});
@@ -106,7 +106,7 @@ context(
// 0004-EWAL-005
it('should have account number visible', function () {
cy.get(walletContainer).within(() => {
cy.get(accountNo)
cy.getByTestId(accountNo)
.should('be.visible')
.and('have.text', Cypress.env('ethWalletPublicKeyTruncated'));
});
@@ -129,7 +129,7 @@ context(
// 0004-EWAL-007
it('should have Disconnect button visible', function () {
cy.get(walletContainer).within(() => {
cy.get(disconnect)
cy.getByTestId(disconnect)
.should('be.visible')
.and('have.text', 'Disconnect');
});
@@ -7,28 +7,28 @@ import {
const walletContainer = 'aside [data-testid="vega-wallet"]';
const walletHeader = '[data-testid="wallet-header"] h1';
const connectButton = '[data-testid="connect-vega-wallet"]';
const getVegaLink = '[data-testid="link"]';
const connectButton = 'connect-vega-wallet';
const getVegaLink = 'link';
const dialog = '[role="dialog"]:visible';
const dialogHeader = '[data-testid="dialog-title"]';
const walletDialogHeader = '[data-testid="wallet-dialog-title"]';
const connectorsList = '[data-testid="connectors-list"]';
const dialogCloseBtn = '[data-testid="dialog-close"]';
const restConnectorForm = '[data-testid="rest-connector-form"]';
const dialogHeader = 'dialog-title';
const walletDialogHeader = 'wallet-dialog-title';
const connectorsList = 'connectors-list';
const dialogCloseBtn = 'dialog-close';
const restConnectorForm = 'rest-connector-form';
const restWallet = '#wallet';
const restPassphrase = '#passphrase';
const restConnectBtn = '[type="submit"]';
const accountNo = '[data-testid="vega-account-truncated"]';
const currencyTitle = '[data-testid="currency-title"]';
const currencyValue = '[data-testid="currency-value"]';
const accountNo = 'vega-account-truncated';
const currencyTitle = 'currency-title';
const currencyValue = 'currency-value';
const vegaUnstaked = '[data-testid="vega-wallet-balance-unstaked"] .text-right';
const governanceBtn = '[href="/proposals"]';
const stakingBtn = '[href="/validators"]';
const manageLink = '[data-testid="manage-vega-wallet"]';
const dialogVegaKey = '[data-testid="vega-public-key-full"]';
const dialogDisconnectBtn = '[data-testid="disconnect"]';
const copyPublicKeyBtn = '[data-testid="copy-vega-public-key"]';
const vegaWalletCurrencyTitle = '[data-testid="currency-title"]';
const manageLink = 'manage-vega-wallet';
const dialogVegaKey = 'vega-public-key-full';
const dialogDisconnectBtn = 'disconnect';
const copyPublicKeyBtn = 'copy-vega-public-key';
const vegaWalletCurrencyTitle = 'currency-title';
const vegaWalletPublicKey = Cypress.env('vegaWalletPublicKey');
const txTimeout = Cypress.env('txTimeout');
@@ -47,10 +47,10 @@ context(
cy.get(walletHeader)
.should('be.visible')
.and('have.text', 'Vega Wallet');
cy.get(connectButton)
cy.getByTestId(connectButton)
.should('be.visible')
.and('have.text', 'Connect Vega wallet to use associated $VEGA');
cy.get(getVegaLink)
cy.getByTestId(getVegaLink)
.should('be.visible')
.and('have.text', 'Get a Vega wallet')
.and('have.attr', 'href', 'https://vega.xyz/wallet');
@@ -61,20 +61,20 @@ context(
describe('when connect button clicked', () => {
before('click connect vega wallet button', () => {
cy.get(walletContainer).within(() => {
cy.get(connectButton).click();
cy.getByTestId(connectButton).click();
});
});
it('should have Connect Vega header visible', () => {
cy.get(dialog).within(() => {
cy.get(walletDialogHeader)
cy.getByTestId(walletDialogHeader)
.should('be.visible')
.and('have.text', 'Connect');
});
});
it('should have jsonRpc and hosted connection options visible on list', function () {
cy.get(connectorsList).within(() => {
cy.getByTestId(connectorsList).within(() => {
cy.getByTestId('connector-jsonRpc')
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
@@ -86,33 +86,33 @@ context(
it('should have close button visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogCloseBtn).should('be.visible');
cy.getByTestId(dialogCloseBtn).should('be.visible');
});
});
});
describe('when rest connector form opened', function () {
before('click hosted wallet app button', function () {
cy.get(connectorsList).within(() => {
cy.getByTestId(connectorsList).within(() => {
cy.getByTestId('connector-hosted').click();
});
});
// 0002-WCON-002
it('should have wallet field visible', function () {
cy.get(restConnectorForm).within(() => {
cy.getByTestId(restConnectorForm).within(() => {
cy.get(restWallet).should('be.visible');
});
});
it('should have password field visible', function () {
cy.get(restConnectorForm).within(() => {
cy.getByTestId(restConnectorForm).within(() => {
cy.get(restPassphrase).should('be.visible');
});
});
it('should have connect button visible', function () {
cy.get(restConnectorForm).within(() => {
cy.getByTestId(restConnectorForm).within(() => {
cy.get(restConnectBtn)
.should('be.visible')
.and('have.text', 'Connect');
@@ -121,12 +121,12 @@ context(
it('should have close button visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogCloseBtn).should('be.visible');
cy.getByTestId(dialogCloseBtn).should('be.visible');
});
});
after('close dialog', function () {
cy.get(dialogCloseBtn).click().should('not.exist');
cy.getByTestId(dialogCloseBtn).click().should('not.exist');
});
});
@@ -152,7 +152,7 @@ context(
{ tags: '@smoke' },
function () {
cy.get(walletContainer).within(() => {
cy.get(accountNo)
cy.getByTestId(accountNo)
.should('be.visible')
.and('have.text', Cypress.env('vegaWalletPublicKeyShort'));
});
@@ -161,7 +161,7 @@ context(
it('should have Vega Associated currency title visible', function () {
cy.get(walletContainer).within(() => {
cy.get(currencyTitle)
cy.getByTestId(currencyTitle)
.should('be.visible')
.and('contain.text', `VEGAAssociated`);
});
@@ -172,7 +172,7 @@ context(
{ tags: '@smoke' },
function () {
cy.get(walletContainer).within(() => {
cy.get(currencyValue)
cy.getByTestId(currencyValue)
.should('be.visible')
.and('contain.text', `0.00`);
});
@@ -204,21 +204,23 @@ context(
it('should have Manage link visible', function () {
cy.get(walletContainer).within(() => {
cy.get(manageLink).should('be.visible').and('have.text', 'Manage');
cy.getByTestId(manageLink)
.should('be.visible')
.and('have.text', 'Manage');
});
});
describe('when Manage dialog opened', function () {
before('click Manage link', function () {
cy.get(walletContainer).within(() => {
cy.get(manageLink).click();
cy.getByTestId(manageLink).click();
});
});
// 0002-WCON-025, 0002-WCON-026
it('should have SELECT A VEGA KEY dialog title visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogHeader)
cy.getByTestId(dialogHeader)
.should('be.visible')
.and('have.text', 'SELECT A VEGA KEY');
});
@@ -238,7 +240,7 @@ context(
'contain.text',
truncatedPubKey1
);
cy.get(dialogVegaKey)
cy.getByTestId(dialogVegaKey)
.should('be.visible')
.and('contain.text', truncatedPubKey1)
.and('contain.text', truncatedPubKey2);
@@ -248,7 +250,7 @@ context(
// 0002-WCON-029
it('should have copy public key button visible', function () {
cy.get(dialog).within(() => {
cy.get(copyPublicKeyBtn)
cy.getByTestId(copyPublicKeyBtn)
.should('be.visible')
.and('contain.text', 'Copy');
});
@@ -256,13 +258,13 @@ context(
it('should have close button visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogCloseBtn).should('be.visible');
cy.getByTestId(dialogCloseBtn).should('be.visible');
});
});
it('should have vega Disconnect all keys button visible', function () {
cy.get(dialog).within(() => {
cy.get(dialogDisconnectBtn)
cy.getByTestId(dialogDisconnectBtn)
.should('be.visible')
.and('have.text', 'Disconnect all keys');
});
@@ -271,10 +273,10 @@ context(
// 0002-WCON-022
it('should be able to disconnect all keys', function () {
cy.get(dialog).within(() => {
cy.get(dialogDisconnectBtn).click();
cy.getByTestId(dialogDisconnectBtn).click();
});
cy.get(walletContainer).within(() => {
cy.get(connectButton).should('be.visible'); // 0002-WCON-023
cy.getByTestId(connectButton).should('be.visible'); // 0002-WCON-023
});
});
});
@@ -319,16 +321,22 @@ context(
cy.reload();
waitForSpinner();
cy.connectVegaWallet();
cy.get(walletContainer).within(() => {
cy.getByTestId('currency-title', txTimeout).should(
'have.length.at.least',
5
);
});
});
for (const { name, symbol, expectedAmount } of assets) {
it(`should see ${name} within vega wallet`, () => {
cy.get(walletContainer).within(() => {
cy.get(vegaWalletCurrencyTitle)
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name, txTimeout)
.should('be.visible');
cy.get(vegaWalletCurrencyTitle)
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name)
.parent()
.siblings()
@@ -337,7 +345,7 @@ context(
expect(displayedAmount).be.gte(expectedAmount);
});
cy.get(vegaWalletCurrencyTitle)
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name)
.parent()
.contains(symbol);
@@ -5,8 +5,6 @@ import {
verifyTabHighlighted,
} from '../../support/common.functions';
const connectToVegaBtn = '[data-testid="connect-to-vega-wallet-btn"]';
context(
'Withdraw Page - verify elements on page',
{ tags: '@smoke' },
@@ -26,7 +24,7 @@ context(
});
it('should have connect Vega wallet button', function () {
cy.get(connectToVegaBtn)
cy.getByTestId('connect-to-vega-wallet-btn')
.should('be.visible')
.and('have.text', 'Connect Vega wallet');
});
@@ -139,6 +139,9 @@ async function vegaWalletTeardownStaking(stakingBridgeContract: StakingBridge) {
$associatedAmount
);
});
// Wait needed to allow Eth transaction to complete - otherwise could result in nonce error
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
}
});
});
-5
View File
@@ -1,5 +0,0 @@
function ReactMarkdown({ children }) {
return <div>{children}</div>;
}
export default ReactMarkdown;
@@ -0,0 +1,69 @@
import { render, fireEvent } from '@testing-library/react';
import { CollapsibleToggle } from './collapsible-toggle';
describe('CollapsibleToggle', () => {
const testId = 'collapsible-toggle';
it('renders without crashing', () => {
const mockSetToggleState = jest.fn();
const { getByTestId, getByText } = render(
<CollapsibleToggle
toggleState={false}
setToggleState={mockSetToggleState}
dataTestId={testId}
>
<div>Test</div>
</CollapsibleToggle>
);
expect(getByTestId(testId)).toBeInTheDocument();
expect(getByText('Test')).toBeInTheDocument();
});
it('calls setToggleState with the opposite of current toggleState when clicked', () => {
const mockSetToggleState = jest.fn();
const { getByTestId } = render(
<CollapsibleToggle
toggleState={false}
setToggleState={mockSetToggleState}
dataTestId={testId}
>
<div>Test</div>
</CollapsibleToggle>
);
fireEvent.click(getByTestId(testId));
expect(mockSetToggleState).toHaveBeenCalledWith(true);
});
it('has the rotate-180 class if toggleState is true', () => {
const mockSetToggleState = jest.fn();
const { getByTestId } = render(
<CollapsibleToggle
toggleState={true}
setToggleState={mockSetToggleState}
dataTestId={testId}
>
<div>Test</div>
</CollapsibleToggle>
);
expect(getByTestId('toggle-icon-wrapper')).toHaveClass('rotate-180');
});
it('does not have the rotate-180 class if toggleState is false', () => {
const mockSetToggleState = jest.fn();
const { getByTestId } = render(
<CollapsibleToggle
toggleState={false}
setToggleState={mockSetToggleState}
dataTestId={testId}
>
<div>Test</div>
</CollapsibleToggle>
);
expect(getByTestId('toggle-icon-wrapper')).not.toHaveClass('rotate-180');
});
});
@@ -0,0 +1,38 @@
import classnames from 'classnames';
import { Icon } from '@vegaprotocol/ui-toolkit';
import type { Dispatch, SetStateAction, ReactNode } from 'react';
interface CollapsibleToggleProps {
toggleState: boolean;
setToggleState: Dispatch<SetStateAction<boolean>>;
children: ReactNode;
dataTestId?: string;
}
export const CollapsibleToggle = ({
toggleState,
setToggleState,
dataTestId,
children,
}: CollapsibleToggleProps) => {
const classes = classnames(
'mb-4 transition-transform ease-in-out duration-300',
{
'rotate-180': toggleState,
}
);
return (
<button
onClick={() => setToggleState(!toggleState)}
data-testid={dataTestId}
>
<div className="flex items-center gap-3">
{children}
<div className={classes} data-testid="toggle-icon-wrapper">
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
);
};
@@ -0,0 +1 @@
export * from './collapsible-toggle';
@@ -833,5 +833,9 @@
"multisigContractIncorrect": "is incorrectly configured. Validator and delegator rewards will be penalised until this is resolved.",
"learnMore": "Learn more",
"AllValidators": "All validators",
"AllProposals": "All proposals"
"AllProposals": "All proposals",
"RejectedProposals": "Rejected proposals",
"networkGovernance": "Network governance",
"networkUpgrades": "Network upgrades",
"assetSpecification": "Asset specification"
}
@@ -1,6 +0,0 @@
import classnames from 'classnames';
export const collapsibleToggleStyles = (toggleState: boolean) =>
classnames('mb-4 transition-transform ease-in-out duration-300', {
'rotate-180': toggleState,
});
@@ -0,0 +1 @@
export * from './proposal-asset-details';
@@ -0,0 +1,48 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { SubHeading } from '../../../../components/heading';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import { AssetDetail, AssetDetailsTable } from '@vegaprotocol/assets';
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
export const ProposalAssetDetails = ({
asset,
}: {
asset: AssetFieldsFragment;
}) => {
const { t } = useTranslation();
const [showAssetDetails, setShowAssetDetails] = useState(false);
return (
<section data-testid="proposal-asset-details">
<CollapsibleToggle
toggleState={showAssetDetails}
setToggleState={setShowAssetDetails}
dataTestId={'proposal-asset-details-toggle'}
>
<SubHeading title={t('assetSpecification')} />
</CollapsibleToggle>
{showAssetDetails && (
<div className="mb-10 pb-4">
<AssetDetailsTable
asset={asset}
omitRows={[
AssetDetail.STATUS,
AssetDetail.INFRASTRUCTURE_FEE_ACCOUNT_BALANCE,
AssetDetail.GLOBAL_REWARD_POOL_ACCOUNT_BALANCE,
AssetDetail.MAKER_PAID_FEES_ACCOUNT_BALANCE,
AssetDetail.MAKER_RECEIVED_FEES_ACCOUNT_BALANCE,
AssetDetail.LP_FEE_REWARD_ACCOUNT_BALANCE,
AssetDetail.MARKET_PROPOSER_REWARD_ACCOUNT_BALANCE,
]}
inline={true}
noBorder={true}
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"
/>
</div>
)}
</section>
);
};
@@ -1,9 +1,9 @@
import ReactMarkdown from 'react-markdown';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
export const ProposalDescription = ({
description,
@@ -15,17 +15,13 @@ export const ProposalDescription = ({
return (
<section data-testid="proposal-description">
<button
onClick={() => setShowDescription(!showDescription)}
data-testid="proposal-description-toggle"
<CollapsibleToggle
toggleState={showDescription}
setToggleState={setShowDescription}
dataTestId={'proposal-description-toggle'}
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalDescription')} />
<div className={collapsibleToggleStyles(showDescription)}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
<SubHeading title={t('proposalDescription')} />
</CollapsibleToggle>
{showDescription && (
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
@@ -1,8 +1,8 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
@@ -16,17 +16,13 @@ export const ProposalJson = ({
return (
<section data-testid="proposal-json">
<button
onClick={() => setShowDetails(!showDetails)}
data-testid="proposal-json-toggle"
<CollapsibleToggle
toggleState={showDetails}
setToggleState={setShowDetails}
dataTestId="proposal-json-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalJson')} />
<div className={collapsibleToggleStyles(showDetails)}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
<SubHeading title={t('proposalJson')} />
</CollapsibleToggle>
{showDetails && <SyntaxHighlighter data={proposal} />}
</section>
@@ -24,7 +24,7 @@ import {
SyntaxHighlighter,
} from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { MarketInfoWithData } from '@vegaprotocol/markets';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import { create } from 'zustand';
@@ -77,17 +77,13 @@ export const ProposalMarketData = ({
return (
<section className="relative" data-testid="proposal-market-data">
<button
onClick={() => setShowDetails(!showDetails)}
data-testid="proposal-market-data-toggle"
<CollapsibleToggle
toggleState={showDetails}
setToggleState={setShowDetails}
dataTestId="proposal-market-data-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('marketSpecification')} />
<div className={collapsibleToggleStyles(showDetails)}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
<SubHeading title={t('marketSpecification')} />
</CollapsibleToggle>
{showDetails && (
<>
@@ -5,14 +5,13 @@ import {
KeyValueTableRow,
Thumbs,
RoundedWrapper,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { formatNumber, formatNumberPercentage } from '@vegaprotocol/utils';
import { SubHeading } from '../../../../components/heading';
import { useVoteInformation } from '../../hooks';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { ProposalType } from '../proposal/proposal';
import { collapsibleToggleStyles } from '../../../../lib/collapsible-toggle-styles';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
@@ -59,17 +58,13 @@ export const ProposalVotesTable = ({
return (
<>
<button
onClick={() => setShowDetails(!showDetails)}
data-testid="vote-breakdown-toggle"
<CollapsibleToggle
toggleState={showDetails}
setToggleState={setShowDetails}
dataTestId="vote-breakdown-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('voteBreakdown')} />
<div className={collapsibleToggleStyles(showDetails)}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
<SubHeading title={t('voteBreakdown')} />
</CollapsibleToggle>
{showDetails && (
<RoundedWrapper marginBottomLarge={true} paddingBottom={true}>
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react';
import { generateProposal } from '../../test-helpers/generate-proposals';
import { Proposal } from './proposal';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { ProposalState } from '@vegaprotocol/types';
jest.mock('@vegaprotocol/network-parameters', () => ({
...jest.requireActual('@vegaprotocol/network-parameters'),
@@ -64,6 +65,17 @@ it('Renders with a link back to "all proposals"', async () => {
expect(await screen.findByTestId('all-proposals-link')).toBeInTheDocument();
});
it('Renders a rejected proposals with a link back to "rejected proposals"', async () => {
const proposal = generateProposal({
state: ProposalState.STATE_REJECTED,
});
renderComponent(proposal);
expect(
await screen.findByTestId('rejected-proposals-link')
).toBeInTheDocument();
});
it('renders each section', async () => {
const proposal = generateProposal();
renderComponent(proposal);
@@ -10,6 +10,7 @@ import { ProposalDescription } from '../proposal-description';
import { ProposalChangeTable } from '../proposal-change-table';
import { ProposalJson } from '../proposal-json';
import { ProposalVotesTable } from '../proposal-votes-table';
import { ProposalAssetDetails } from '../proposal-asset-details';
import { VoteDetails } from '../vote-details';
import { ListAsset } from '../list-asset';
import Routes from '../../../routes';
@@ -17,6 +18,9 @@ import { ProposalMarketData } from '../proposal-market-data';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { MarketInfoWithData } from '@vegaprotocol/markets';
import type { AssetQuery } from '@vegaprotocol/assets';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { ProposalState } from '@vegaprotocol/types';
export enum ProposalType {
PROPOSAL_NEW_MARKET = 'PROPOSAL_NEW_MARKET',
@@ -29,6 +33,7 @@ export enum ProposalType {
export interface ProposalProps {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
newMarketData?: MarketInfoWithData | null;
assetData?: AssetQuery | null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
restData: any;
}
@@ -37,6 +42,7 @@ export const Proposal = ({
proposal,
restData,
newMarketData,
assetData,
}: ProposalProps) => {
const { t } = useTranslation();
const { params, loading, error } = useNetworkParams([
@@ -53,6 +59,23 @@ export const Proposal = ({
return null;
}
let asset = assetData
? removePaginationWrapper(assetData.assetsConnection?.edges)[0]
: undefined;
if (proposal.terms.change.__typename === 'UpdateAsset' && asset) {
asset = {
...asset,
quantum: proposal.terms.change.quantum,
};
if (asset.source.__typename === 'ERC20') {
asset.source.lifetimeLimit = proposal.terms.change.source.lifetimeLimit;
asset.source.withdrawThreshold =
proposal.terms.change.source.withdrawThreshold;
}
}
let minVoterBalance = null;
let proposalType = null;
@@ -91,14 +114,22 @@ export const Proposal = ({
return (
<AsyncRenderer data={params} loading={loading} error={error}>
<section data-testid="proposal">
<div
className="flex items-center gap-1"
data-testid="all-proposals-link"
>
<div className="flex items-center gap-1">
<Icon name={'chevron-left'} />
<Link className="underline" to={Routes.PROPOSALS}>
{t('AllProposals')}
</Link>
{proposal.state === ProposalState.STATE_REJECTED ? (
<div data-testid="rejected-proposals-link">
<Link className="underline" to={Routes.PROPOSALS_REJECTED}>
{t('RejectedProposals')}
</Link>
</div>
) : (
<div data-testid="all-proposals-link">
<Link className="underline" to={Routes.PROPOSALS}>
{t('AllProposals')}
</Link>
</div>
)}
</div>
<ProposalHeader proposal={proposal} isListItem={false} />
@@ -129,6 +160,14 @@ export const Proposal = ({
</div>
)}
{(proposal.terms.change.__typename === 'NewAsset' ||
proposal.terms.change.__typename === 'UpdateAsset') &&
asset && (
<div className="mb-4">
<ProposalAssetDetails asset={asset} />
</div>
)}
<div className="mb-6">
<ProposalJson proposal={restData?.data?.proposal} />
</div>
@@ -0,0 +1,34 @@
import { render, fireEvent, screen } from '@testing-library/react';
import { ProposalsListFilter } from './proposals-list-filter';
describe('ProposalsListFilter', () => {
let setFilterString: jest.Mock;
beforeEach(() => {
setFilterString = jest.fn();
render(
<ProposalsListFilter filterString="" setFilterString={setFilterString} />
);
});
it('renders successfully', () => {
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
});
it('should handle the filter toggle click', () => {
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
});
it('should handle input change', () => {
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'test' },
});
expect(setFilterString).toHaveBeenCalledWith('test');
});
// 'clear filter' tests are handled in the proposals-list.spec.tsx file
// as it is responsible for the filter state
});
@@ -1,13 +1,16 @@
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import { ButtonLink, FormGroup, Input } from '@vegaprotocol/ui-toolkit';
import { FormGroup, Icon, Input } from '@vegaprotocol/ui-toolkit';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
import type { Dispatch, SetStateAction } from 'react';
interface ProposalsListFilterProps {
filterString: string;
setFilterString: Dispatch<SetStateAction<string>>;
}
export const ProposalsListFilter = ({
filterString,
setFilterString,
}: ProposalsListFilterProps) => {
const { t } = useTranslation();
@@ -15,27 +18,39 @@ export const ProposalsListFilter = ({
return (
<div data-testid="proposals-list-filter" className="mb-4">
{!filterVisible && (
<ButtonLink
onClick={() => setFilterVisible(true)}
data-testid="set-proposals-filter-visible"
>
{t('FilterProposals')}
</ButtonLink>
)}
<CollapsibleToggle
toggleState={filterVisible}
setToggleState={setFilterVisible}
dataTestId={'proposal-filter-toggle'}
>
<div className="text-xl mb-4">{t('FilterProposals')}</div>
</CollapsibleToggle>
{filterVisible && (
<div data-testid="open-proposals-list-filter">
<div data-testid="proposals-list-filter-visible">
<p>{t('FilterProposalsDescription')}</p>
<FormGroup
label="Filter text input"
labelFor="filter-input"
hideLabel={true}
className="relative"
>
<Input
value={filterString}
data-testid="filter-input"
id="filter-input"
onChange={(e) => setFilterString(e.target.value)}
className="pr-8"
/>
{filterString && filterString.length > 0 && (
<button
className="absolute top-2 right-2"
onClick={() => setFilterString('')}
data-testid="clear-filter"
>
<Icon name="cross" size={6} className="text-vega-light-200" />
</button>
)}
</FormGroup>
</div>
)}
@@ -1,4 +1,7 @@
import { generateProposal } from '../../test-helpers/generate-proposals';
import {
generateProposal,
generateProtocolUpgradeProposal,
} from '../../test-helpers/generate-proposals';
import { MockedProvider } from '@apollo/client/testing';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { BrowserRouter as Router } from 'react-router-dom';
@@ -15,6 +18,7 @@ import {
nextMonth,
} from '../../test-helpers/mocks';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
const openProposalClosesNextMonth = generateProposal({
id: 'proposal1',
@@ -54,12 +58,22 @@ const failedProposalClosedLastMonth = generateProposal({
},
});
const renderComponent = (proposals: ProposalQuery['proposal'][]) => (
const closedProtocolUpgradeProposal = generateProtocolUpgradeProposal({
upgradeBlockHeight: '1',
});
const renderComponent = (
proposals: ProposalQuery['proposal'][],
protocolUpgradeProposals?: ProtocolUpgradeProposalFieldsFragment[]
) => (
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposalsList proposals={proposals} protocolUpgradeProposals={[]} />
<ProposalsList
proposals={proposals}
protocolUpgradeProposals={protocolUpgradeProposals || []}
/>
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
@@ -143,17 +157,15 @@ describe('Proposals list', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
expect(
screen.getByTestId('open-proposals-list-filter')
).toBeInTheDocument();
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
expect(screen.getByTestId('proposals-list-filter')).toBeInTheDocument();
});
it('Filters list by text - party id', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'bvcx' },
});
@@ -166,7 +178,7 @@ describe('Proposals list', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'proposal1' },
});
@@ -179,7 +191,7 @@ describe('Proposals list', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('set-proposals-filter-visible'));
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'osal1' },
});
@@ -187,4 +199,92 @@ describe('Proposals list', () => {
expect(container.querySelector('#proposal1')).toBeInTheDocument();
expect(container.querySelector('#proposal2')).not.toBeInTheDocument();
});
it('When filter is used, clear button is visible', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'test' },
});
expect(screen.getByTestId('clear-filter')).toBeInTheDocument();
});
it('When clear filter button is used, input is cleared', () => {
render(
renderComponent([openProposalClosesNextMonth, openProposalClosesNextWeek])
);
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'test' },
});
fireEvent.click(screen.getByTestId('clear-filter'));
expect((screen.getByTestId('filter-input') as HTMLInputElement).value).toBe(
''
);
});
it('Displays a toggle for closed proposals if there are both closed governance proposals and closed upgrade proposals', () => {
render(
renderComponent(
[enactedProposalClosedLastWeek],
[closedProtocolUpgradeProposal]
)
);
expect(screen.getByTestId('toggle-closed-proposals')).toBeInTheDocument();
});
it('Does not display a toggle for closed proposals if there are only closed upgrade proposals', () => {
render(renderComponent([], [closedProtocolUpgradeProposal]));
expect(
screen.queryByTestId('toggle-closed-proposals')
).not.toBeInTheDocument();
});
it('Does not display a toggle for closed proposals if there are only closed governance proposals', () => {
render(renderComponent([enactedProposalClosedLastWeek]));
expect(
screen.queryByTestId('toggle-closed-proposals')
).not.toBeInTheDocument();
});
it('Does not display a toggle for closed proposals if the proposal filter is engaged', () => {
render(
renderComponent(
[enactedProposalClosedLastWeek],
[closedProtocolUpgradeProposal]
)
);
fireEvent.click(screen.getByTestId('proposal-filter-toggle'));
fireEvent.change(screen.getByTestId('filter-input'), {
target: { value: 'test' },
});
expect(
screen.queryByTestId('toggle-closed-proposals')
).not.toBeInTheDocument();
});
it('Displays closed governance proposals by default due to default for the toggle', () => {
render(
renderComponent(
[enactedProposalClosedLastWeek],
[closedProtocolUpgradeProposal]
)
);
expect(
screen.getByTestId('closed-governance-proposals')
).toBeInTheDocument();
});
it('Displays closed upgrade proposals when the toggle is clicked', () => {
render(
renderComponent(
[enactedProposalClosedLastWeek],
[closedProtocolUpgradeProposal]
)
);
fireEvent.click(screen.getByText('Network upgrades'));
expect(screen.getByTestId('closed-upgrade-proposals')).toBeInTheDocument();
});
});
@@ -7,7 +7,12 @@ import { ProposalsListItem } from '../proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import { ProposalsListFilter } from '../proposals-list-filter';
import Routes from '../../../routes';
import { Button, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import {
Button,
Toggle,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { Link } from 'react-router-dom';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
@@ -54,6 +59,11 @@ export const orderByUpgradeBlockHeight = (
['desc', 'desc']
);
enum ClosedProposalsViewOptions {
NetworkGovernance = 'networkGovernance',
NetworkUpgrades = 'networkUpgrades',
}
export const ProposalsList = ({
proposals,
protocolUpgradeProposals,
@@ -61,6 +71,10 @@ export const ProposalsList = ({
}: ProposalsListProps) => {
const { t } = useTranslation();
const [filterString, setFilterString] = useState('');
const [closedProposalsView, setClosedProposalsView] =
useState<ClosedProposalsViewOptions>(
ClosedProposalsViewOptions.NetworkGovernance
);
const sortedProposals: SortedProposalsProps = useMemo(() => {
const initialSorting = proposals.reduce(
@@ -109,7 +123,7 @@ export const ProposalsList = ({
);
return {
open: orderByUpgradeBlockHeight(initialSorting.open),
closed: orderByUpgradeBlockHeight(initialSorting.closed).reverse(),
closed: orderByUpgradeBlockHeight(initialSorting.closed),
};
}, [protocolUpgradeProposals, lastBlockHeight]);
@@ -127,6 +141,7 @@ export const ProposalsList = ({
marginBottom={false}
title={t('pageTitleProposals')}
/>
{DocsLinks && (
<div className="xs:justify-self-end" data-testid="new-proposal-link">
<ExternalLink href={DocsLinks.PROPOSALS_GUIDE}>
@@ -140,6 +155,7 @@ export const ProposalsList = ({
</div>
)}
</div>
<p className="mb-8">
{t(
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network. Network upgrades are proposed and approved by validators.`
@@ -152,20 +168,37 @@ export const ProposalsList = ({
{t(`Find out more about Vega governance`)}
</ExternalLink>
</p>
{proposals.length > 0 && (
<ProposalsListFilter setFilterString={setFilterString} />
<ProposalsListFilter
filterString={filterString}
setFilterString={(value) => {
setFilterString(value);
if (value.length > 0) {
// If the filter is engaged, ensure the user is viewing governance proposals,
// as network upgrades do not have IDs to filter by and will be excluded.
setClosedProposalsView(
ClosedProposalsViewOptions.NetworkGovernance
);
}
}}
/>
)}
<section className="-mx-4 p-4 mb-8 bg-vega-dark-100">
<SubHeading title={t('openProposals')} />
{sortedProposals.open.length > 0 ||
sortedProtocolUpgradeProposals.open.length > 0 ? (
<ul data-testid="open-proposals">
{sortedProtocolUpgradeProposals.open.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
{filterString.length < 1 &&
sortedProtocolUpgradeProposals.open.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
{sortedProposals.open.filter(filterPredicate).map((proposal) => (
<ProposalsListItem key={proposal?.id} proposal={proposal} />
))}
@@ -176,22 +209,81 @@ export const ProposalsList = ({
</p>
)}
</section>
<section>
<section className="relative">
<SubHeading title={t('closedProposals')} />
{sortedProposals.closed.length > 0 ||
sortedProtocolUpgradeProposals.closed.length > 0 ? (
<ul data-testid="closed-proposals">
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
<>
{
// We need both the closed proposals and closed protocol upgrade
// proposals to be present for there to be a toggle. It also gets
// hidden if the user has filtered the list, as the upgrade proposals
// do not have the necessary fields for filtering.
sortedProposals.closed.length > 0 &&
sortedProtocolUpgradeProposals.closed.length > 0 &&
filterString.length < 1 && (
<div
className="grid w-full justify-end xl:-mt-12 pb-6"
data-testid="toggle-closed-proposals"
>
<div className="w-[440px]">
<Toggle
name="closed-proposals-toggle"
toggles={[
{
label: t(
ClosedProposalsViewOptions.NetworkGovernance
),
value: ClosedProposalsViewOptions.NetworkGovernance,
},
{
label: t(
ClosedProposalsViewOptions.NetworkUpgrades
),
value: ClosedProposalsViewOptions.NetworkUpgrades,
},
]}
checkedValue={closedProposalsView}
onChange={(e) =>
setClosedProposalsView(
e.target.value as ClosedProposalsViewOptions
)
}
/>
</div>
</div>
)
}
{sortedProposals.closed.filter(filterPredicate).map((proposal) => (
<ProposalsListItem key={proposal?.id} proposal={proposal} />
))}
</ul>
<ul data-testid="closed-proposals">
{closedProposalsView ===
ClosedProposalsViewOptions.NetworkUpgrades && (
<div data-testid="closed-upgrade-proposals">
{sortedProtocolUpgradeProposals.closed.map((proposal) => (
<ProtocolUpgradeProposalsListItem
key={proposal.upgradeBlockHeight}
proposal={proposal}
/>
))}
</div>
)}
{closedProposalsView ===
ClosedProposalsViewOptions.NetworkGovernance && (
<div data-testid="closed-governance-proposals">
{sortedProposals.closed
.filter(filterPredicate)
.map((proposal) => (
<ProposalsListItem
key={proposal?.id}
proposal={proposal}
/>
))}
</div>
)}
</ul>
</>
) : (
<p className="mb-0" data-testid="no-closed-proposals">
{t('noClosedProposals')}
@@ -23,7 +23,10 @@ export const RejectedProposalsList = ({ proposals }: ProposalsListProps) => {
return (
<>
<Heading title={t('pageTitleRejectedProposals')} />
<ProposalsListFilter setFilterString={setFilterString} />
<ProposalsListFilter
filterString={filterString}
setFilterString={setFilterString}
/>
<section>
{proposals.length > 0 ? (
<ul data-testid="rejected-proposals">
@@ -9,6 +9,7 @@ import { useFetch } from '@vegaprotocol/react-helpers';
import { ENV } from '../../../config';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
import { useAssetQuery } from '@vegaprotocol/assets';
export const ProposalContainer = () => {
const params = useParams<{ proposalId: string }>();
@@ -35,6 +36,25 @@ export const ProposalContainer = () => {
},
});
const {
data: assetData,
loading: assetLoading,
error: assetError,
} = useAssetQuery({
fetchPolicy: 'network-only',
variables: {
assetId:
(data?.proposal?.terms.change.__typename === 'NewAsset' &&
data?.proposal?.id) ||
(data?.proposal?.terms.change.__typename === 'UpdateAsset' &&
data.proposal.terms.change.assetId) ||
'',
},
skip: !['NewAsset', 'UpdateAsset'].includes(
data?.proposal?.terms?.change?.__typename || ''
),
});
useEffect(() => {
const interval = setInterval(refetch, 2000);
return () => clearInterval(interval);
@@ -42,15 +62,20 @@ export const ProposalContainer = () => {
return (
<AsyncRenderer
loading={loading || newMarketLoading}
error={error || newMarketError}
data={newMarketData ? { newMarketData, data } : data}
loading={loading || newMarketLoading || assetLoading}
error={error || newMarketError || assetError}
data={{
...data,
...(newMarketData ? { newMarketData } : {}),
...(assetData ? { assetData } : {}),
}}
>
{data?.proposal ? (
<Proposal
proposal={data.proposal}
restData={restData}
newMarketData={newMarketData}
assetData={assetData}
/>
) : (
<ProposalNotFound />
@@ -1,4 +1,5 @@
import * as Schema from '@vegaprotocol/types';
import { ProtocolUpgradeProposalStatus } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import * as faker from 'faker';
import isArray from 'lodash/isArray';
@@ -6,6 +7,40 @@ import mergeWith from 'lodash/mergeWith';
import type { PartialDeep } from 'type-fest';
import type { ProposalQuery } from '../proposal/__generated__/Proposal';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
export function generateProtocolUpgradeProposal(
override: PartialDeep<ProtocolUpgradeProposalFieldsFragment> = {}
): ProtocolUpgradeProposalFieldsFragment {
const defaultProposal: ProtocolUpgradeProposalFieldsFragment = {
__typename: 'ProtocolUpgradeProposal',
upgradeBlockHeight: '3917600',
vegaReleaseTag: 'v0.71.6',
approvers: [
'0ac70c4ccc7f961614fe49b93e639ddf916269b7dcf8391db264cefeadf5a6b7',
'63a1755006642bda9ab1bfa84660f944d30a113d1609590ca90c50b24aede472',
'68ed0770fc3e67b74d09c05443243d27e29a8513dc0e8628beb98338cd509159',
'a6e6f7daf8610f9242ab6ab46b394f6fb79cf9533d48051ca7a2f142b8b700a8',
'aad2be546ba83cbcab4c1d57ebe22b4a942f294f54333f1a7c2c9ef0e9fe19bb',
'acc55c7205cfcd5480e0235acab56a01487a39dc858a641fc04df6ba016870ee',
'b7e500deb24cc19bd6ebb2311997f0904ca0d9e51541249e9650ab41fd8ac376',
'cf295dff6d9506e8a905d168a44dfcff2f64bd0a6671783a469f8322959c62e2',
'f4686749895bf51c6df4092ef6be4279c384a3c380c24ea7a2fd20afc602a35d',
],
status:
ProtocolUpgradeProposalStatus.PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED,
};
return mergeWith<
ProtocolUpgradeProposalFieldsFragment,
PartialDeep<ProtocolUpgradeProposalFieldsFragment>
>(defaultProposal, override, (objValue, srcValue) => {
if (!isArray(objValue)) {
return;
}
return srcValue;
});
}
export function generateProposal(
override: PartialDeep<ProposalQuery['proposal']> = {}
@@ -1,28 +1,180 @@
describe('chart', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('config should persist', () => {
cy.getByTestId('Chart').click();
cy.get('[data-testid="tab-chart"] button').as('control-buttons');
cy.get('@control-buttons').each(($button) => {
cy.wrap($button).click();
cy.get(
'[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first'
).click();
});
cy.getByTestId('Depth').click();
cy.getByTestId('Chart').click();
cy.get('@control-buttons').each(($button) => {
cy.wrap($button).click();
cy.get('[role="menuitemradio"]:first, [role="menuitemcheckbox"]:first')
.within(($lastMenuItem) => {
expect($lastMenuItem.data('state')).to.equal('checked');
})
.click();
interface ItemInfoType {
name: string;
infoText: string;
}
type CheckMenuItemsFnType = (
triggerSelector: string,
validTexts: string[],
clickItem?: string
) => void;
type CheckMenuItemCheckboxFnType = (
buttonText: string,
items: ItemInfoType[]
) => void;
const menuItemRadio = 'div[role="menuitemradio"]';
const menuItemCheckbox = 'div[role="menuitemcheckbox"]';
const button = 'button';
const indicatorInfo = '.indicator-info-wrapper';
const checkMenuItems: CheckMenuItemsFnType = (
triggerSelector,
validTexts,
clickItem
) => {
cy.get(triggerSelector).click();
cy.get(menuItemRadio)
.should('have.length', validTexts.length)
.each(($el, index) => {
const text = $el.text().trim();
expect(text).to.equal(validTexts[index]);
});
if (clickItem) {
cy.contains(menuItemRadio, clickItem).click();
cy.get(triggerSelector).click();
cy.get(`${menuItemRadio}[data-state="checked"]`)
.invoke('text')
.then((text: string) => {
expect(text.trim()).to.equal(clickItem);
});
}
};
const checkMenuItemCheckbox: CheckMenuItemCheckboxFnType = (
buttonText,
items
) => {
items.forEach((item) => {
cy.contains(button, buttonText).click();
cy.contains(menuItemCheckbox, item.name).click();
});
cy.contains(button, buttonText).click();
cy.get(menuItemCheckbox)
.should('have.length', items.length)
.each(($el, index) => {
const text = $el.text();
expect(text).to.equal(items[index].name);
});
items.forEach((item, index) => {
cy.get(indicatorInfo)
.eq(index + 1)
.invoke('text')
.should('eq', item.infoText);
});
cy.contains(button, buttonText).click({ force: true });
};
function getButtonSelectorByText(text: string): string {
return `${button}[aria-haspopup="menu"]:contains(${text})`;
}
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
describe(
'chart display options',
{ tags: '@smoke', testIsolation: true },
() => {
it('change time interval', () => {
// 6004-CHAR-001
checkMenuItems(
getButtonSelectorByText('Interval:'),
['1m', '5m', '15m', '1H', '6H', '1D'],
'1m'
);
});
it('change display type', () => {
// 6004-CHAR-002
// 6004-CHAR-003
checkMenuItems(
'[aria-label$="chart icon"]',
['Mountain', 'Candlestick', 'Line', 'OHLC'],
'Mountain'
);
});
it('Overlays', () => {
// 6004-CHAR-004
// 6004-CHAR-008
// 6004-CHAR-009
// 6004-CHAR-034
// 6004-CHAR-037
// 6004-CHAR-039
// 6004-CHAR-041
const overlayInfo: ItemInfoType[] = [
{
name: 'Bollinger bands',
infoText: 'Bollinger: Upper 174.78590Lower 173.38014',
},
{
name: 'Envelope',
infoText: 'Envelope: Upper 191.29000Lower 156.51000',
},
{ name: 'EMA', infoText: 'EMA: 174.06793' },
{ name: 'Moving average', infoText: 'Moving average: 174.08302' },
{
name: 'Price monitoring bounds',
infoText: 'Price Monitoring Bounds: Min -Max -Reference -',
},
];
checkMenuItemCheckbox('Overlays', overlayInfo);
});
it('Studies', () => {
// 6004-CHAR-005
// 6004-CHAR-006
// 6004-CHAR-007
// 6004-CHAR-042
// 6004-CHAR-045
// 6004-CHAR-047
// 6004-CHAR-049
// 6004-CHAR-051
const studyInfo: ItemInfoType[] = [
{
name: 'Eldar-ray',
infoText: 'Eldar-ray: Bull -0.08376Bear -0.58376',
},
{ name: 'Force index', infoText: 'Force index: 987.48858' },
{ name: 'MACD', infoText: 'MACD: S -0.06420D 0.00359MACD -0.06062' },
{ name: 'RSI', infoText: 'RSI: 47.08648' },
{ name: 'Volume', infoText: 'Volume: 55,000.00000' },
];
cy.get(indicatorInfo).eq(1).realHover();
cy.get('.close-button-module_closeButton__2ifkl').click({ force: true });
cy.get(indicatorInfo).should('have.length', 1);
checkMenuItemCheckbox('Studies', studyInfo);
});
it('price details', () => {
// 6004-CHAR-010
const expectedDateRegex = new RegExp(
/^\d{2}:\d{2} \d{2} [A-Za-z]{3} \d{4}$/
);
const expectedOhlc = `O 173.60000H 174.00000L 173.50000C 173.90000Change 0.60000(0.34%)`;
cy.get(indicatorInfo)
.eq(0)
.invoke('text')
.then((text) => {
const actualDate = text.slice(0, -67);
console.log(actualDate);
const actualOhlc = text.slice(-67);
assert.isTrue(expectedDateRegex.test(actualDate));
assert.strictEqual(actualOhlc, expectedOhlc);
});
});
}
);
+1 -1
View File
@@ -14,4 +14,4 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.vega.xyz
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.20.18-core-0.71.8
NX_APP_VERSION=v0.20.19-core-0.71.6
@@ -91,10 +91,7 @@ const MarketBottomPanel = memo(
</Tab>
<Tab id="fills" name={t('Fills')}>
<VegaWalletContainer>
<TradingViews.fills.component
marketId={marketId}
onMarketClick={onMarketClick}
/>
<TradingViews.fills.component onMarketClick={onMarketClick} />
</VegaWalletContainer>
</Tab>
</Tabs>
@@ -166,10 +163,7 @@ const MarketBottomPanel = memo(
</Tab>
<Tab id="fills" name={t('Fills')}>
<VegaWalletContainer>
<TradingViews.fills.component
marketId={marketId}
onMarketClick={onMarketClick}
/>
<TradingViews.fills.component onMarketClick={onMarketClick} />
</VegaWalletContainer>
</Tab>
<Tab id="accounts" name={t('Collateral')}>
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import classNames from 'classnames';
import { truncateByChars } from '@vegaprotocol/utils';
@@ -12,9 +12,10 @@ import {
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
Icon,
Drawer,
DropdownMenuSeparator,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import type { PubKey } from '@vegaprotocol/wallet';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
@@ -249,14 +250,14 @@ const KeypairItem = ({ pk }: { pk: PubKey }) => {
{truncateByChars(pk.publicKey)}
</span>
</span>
<span>
<span className="inline-flex items-center gap-1">
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
<button
data-testid="copy-vega-public-key"
onClick={(e) => e.stopPropagation()}
>
<span className="sr-only">{t('Copy')}</span>
<Icon name="duplicate" className="mr-2" />
<VegaIcon name={VegaIconNames.COPY} />
</button>
</CopyToClipboard>
{copied && (
@@ -278,34 +279,20 @@ const KeypairListItem = ({
isActive: boolean;
onSelectItem: (pk: string) => void;
}) => {
const [copied, setCopied] = useState(false);
useEffect(() => {
// eslint-disable-next-line
let timeout: any;
if (copied) {
timeout = setTimeout(() => {
setCopied(false);
}, 800);
}
return () => {
clearTimeout(timeout);
};
}, [copied]);
const [copied, setCopied] = useCopyTimeout();
return (
<div
className="flex flex-col w-full ml-4 mr-2 mb-4"
data-testid={`key-${pk.publicKey}-mobile`}
>
<span className="mr-2">
<span className="flex gap-2 items-center mr-2">
<button onClick={() => onSelectItem(pk.publicKey)}>
<span className="uppercase">{pk.name}</span>
</button>
{isActive && <Icon name="tick" className="ml-2" />}
{isActive && <VegaIcon name={VegaIconNames.TICK} />}
</span>
<span className="text-neutral-500 dark:text-neutral-400">
<span className="flex gap-2 items-center">
{truncateByChars(pk.publicKey)}{' '}
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
<button
@@ -313,7 +300,7 @@ const KeypairListItem = ({
onClick={(e) => e.stopPropagation()}
>
<span className="sr-only">{t('Copy')}</span>
<Icon name="duplicate" className="mr-2" />
<VegaIcon name={VegaIconNames.COPY} />
</button>
</CopyToClipboard>
{copied && (
@@ -26,9 +26,12 @@ describe('Announcements', () => {
const { container } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
});
await act(
async () =>
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
})
);
});
it('does not display the banner when there are no announcements', async () => {
@@ -42,9 +45,12 @@ describe('Announcements', () => {
const { container } = render(
<AnnouncementBanner app="console" configUrl={MOCK_URL} />
);
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
});
await act(
async () =>
await waitFor(() => {
expect(container.firstChild).toBeEmptyDOMElement();
})
);
});
it('shows the correct announcement', async () => {
@@ -200,8 +206,11 @@ describe('Announcements', () => {
jest.runOnlyPendingTimers();
});
await waitFor(() => {
expect(queryByText('Live text')).not.toBeInTheDocument();
});
await act(
async () =>
await waitFor(() => {
expect(queryByText('Live text')).not.toBeInTheDocument();
})
);
});
});
@@ -80,4 +80,14 @@ describe('AssetDetailsTable', () => {
}
}
);
it('omits specified rows when omitRows prop is provided', async () => {
const asset = generateERC20Asset(1, Schema.AssetStatus.STATUS_ENABLED);
const omittedKeys = [AssetDetail.TYPE, AssetDetail.DECIMALS];
render(<AssetDetailsTable asset={asset} omitRows={omittedKeys} />);
for (const key of omittedKeys) {
expect(screen.queryByTestId(testId(key, 'label'))).toBeNull();
expect(screen.queryByTestId(testId(key, 'value'))).toBeNull();
}
});
});
+3 -1
View File
@@ -224,9 +224,11 @@ export const testId = (detail: AssetDetail, field: 'label' | 'value') =>
export type AssetDetailsTableProps = {
asset: Asset;
omitRows?: AssetDetail[];
} & Omit<KeyValueTableRowProps, 'children'>;
export const AssetDetailsTable = ({
asset,
omitRows = [],
...props
}: AssetDetailsTableProps) => {
const longStringModifiers = (key: AssetDetail, value: string) =>
@@ -243,7 +245,7 @@ export const AssetDetailsTable = ({
return (
<KeyValueTable>
{details
.filter(({ value }) => Boolean(value))
.filter(({ key, value }) => Boolean(value) && !omitRows.includes(key))
.map(({ key, label, value, tooltip, valueTooltip }) => (
<KeyValueTableRow key={key} {...props}>
<div
+240
View File
@@ -78,4 +78,244 @@ const candles: CandleFieldsFragment[] = [
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:00:00Z',
lastUpdateInPeriod: '2022-04-06T09:01:00Z',
high: '17481092',
low: '17403651',
open: '17458833',
close: '17446470',
volume: '82721',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:10:00Z',
lastUpdateInPeriod: '2022-04-06T09:11:00Z',
high: '17491202',
low: '17361138',
open: '17446470',
close: '17367174',
volume: '62637',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:20:00Z',
lastUpdateInPeriod: '2022-04-06T09:21:00Z',
high: '17424522',
low: '17337719',
open: '17367174',
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:30:00Z',
lastUpdateInPeriod: '2022-04-06T09:31:00Z',
high: '17500000',
low: '17300000',
open: '17380000',
close: '17450000',
volume: '70000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:40:00Z',
lastUpdateInPeriod: '2022-04-06T09:41:00Z',
high: '17400000',
low: '17350000',
open: '17360000',
close: '17390000',
volume: '55000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:50:00Z',
lastUpdateInPeriod: '2022-04-06T09:51:00Z',
high: '17481092',
low: '17403651',
open: '17458833',
close: '17446470',
volume: '82721',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T10:00:00Z',
lastUpdateInPeriod: '2022-04-06T10:01:00Z',
high: '17491202',
low: '17361138',
open: '17446470',
close: '17367174',
volume: '62637',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T10:10:00Z',
lastUpdateInPeriod: '2022-04-06T10:11:00Z',
high: '17424522',
low: '17337719',
open: '17367174',
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T10:20:00Z',
lastUpdateInPeriod: '2022-04-06T10:21:00Z',
high: '17500000',
low: '17300000',
open: '17380000',
close: '17450000',
volume: '70000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T10:30:00Z',
lastUpdateInPeriod: '2022-04-06T10:31:00Z',
high: '17400000',
low: '17350000',
open: '17360000',
close: '17390000',
volume: '55000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T01:00:00Z',
lastUpdateInPeriod: '2022-04-06T09:01:00Z',
high: '17481092',
low: '17403651',
open: '17458833',
close: '17446470',
volume: '82721',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:10:00Z',
lastUpdateInPeriod: '2022-04-06T09:11:00Z',
high: '17491202',
low: '17361138',
open: '17446470',
close: '17367174',
volume: '62637',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:20:00Z',
lastUpdateInPeriod: '2022-04-06T09:21:00Z',
high: '17424522',
low: '17337719',
open: '17367174',
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:30:00Z',
lastUpdateInPeriod: '2022-04-06T09:31:00Z',
high: '17500000',
low: '17300000',
open: '17380000',
close: '17450000',
volume: '70000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:40:00Z',
lastUpdateInPeriod: '2022-04-06T09:41:00Z',
high: '17400000',
low: '17350000',
open: '17360000',
close: '17390000',
volume: '55000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T09:50:00Z',
lastUpdateInPeriod: '2022-04-06T09:51:00Z',
high: '17481092',
low: '17403651',
open: '17458833',
close: '17446470',
volume: '82721',
},
{
__typename: 'Candle',
periodStart: '2022-04-05T20:00:00Z',
lastUpdateInPeriod: '2022-04-05T20:01:00Z',
high: '17491202',
low: '17361138',
open: '17446470',
close: '17367174',
volume: '62637',
},
{
__typename: 'Candle',
periodStart: '2022-04-05T22:10:00Z',
lastUpdateInPeriod: '2022-04-05T24:11:00Z',
high: '17424522',
low: '17337719',
open: '17367174',
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-05T21:20:00Z',
lastUpdateInPeriod: '2022-04-05T21:21:00Z',
high: '17500000',
low: '17300000',
open: '17380000',
close: '17450000',
volume: '70000',
},
{
__typename: 'Candle',
periodStart: '2022-04-05T21:30:00Z',
lastUpdateInPeriod: '2022-04-05T21:31:00Z',
high: '17400000',
low: '17350000',
open: '17360000',
close: '17390000',
volume: '55000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T02:00:00Z',
lastUpdateInPeriod: '2022-04-06T02:01:00Z',
high: '17491202',
low: '17361138',
open: '17446470',
close: '17367174',
volume: '62637',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T03:03:00Z',
lastUpdateInPeriod: '2022-04-06T03:11:00Z',
high: '17424522',
low: '17337719',
open: '17367174',
close: '17376455',
volume: '60259',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T00:20:00Z',
lastUpdateInPeriod: '2022-04-06T00:21:00Z',
high: '17500000',
low: '17300000',
open: '17380000',
close: '17450000',
volume: '70000',
},
{
__typename: 'Candle',
periodStart: '2022-04-06T01:30:00Z',
lastUpdateInPeriod: '2022-04-06T01:31:00Z',
high: '17400000',
low: '17350000',
open: '17360000',
close: '17390000',
volume: '55000',
},
];
+2 -1
View File
@@ -4,7 +4,8 @@ import { Networks } from '../types';
import { useEnvironment } from './use-environment';
import { stripFullStops } from '@vegaprotocol/utils';
const VEGA_DOCS_URL = process.env['NX_VEGA_DOCS_URL'] || '';
const VEGA_DOCS_URL =
process.env['NX_VEGA_DOCS_URL'] || 'https://docs.vega.xyz/mainnet';
type Net = Exclude<Networks, 'CUSTOM'>;
export enum DApp {
@@ -6,6 +6,7 @@ import {
GITHUB_VEGA_DEV_RELEASES_DATA,
} from './mocks/github-releases';
import { useVegaRelease } from './use-vega-release';
import { act } from 'react-dom/test-utils';
describe('useVegaRelease', () => {
beforeEach(() => {
@@ -31,8 +32,11 @@ describe('useVegaRelease', () => {
it('should return undefined when a release cannot be found', async () => {
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
await waitFor(() => {
expect(result.current).toEqual(undefined);
});
await act(
async () =>
await waitFor(() => {
expect(result.current).toEqual(undefined);
})
);
});
});
@@ -19,7 +19,6 @@ describe('useOracleMarkets', () => {
it('returns correct market list for the given provider', () => {
mockMarkets.mockReturnValueOnce({ data: marketsData });
const { result } = renderHook(() => useOracleMarkets(mockProvider));
console.log(JSON.stringify(result.current));
expect(result.current).toStrictEqual(oracleMarkets);
});
});
+1 -1
View File
@@ -1,4 +1,4 @@
{
"name": "@vegaprotocol/ui-toolkit",
"version": "0.12.5"
"version": "0.12.6"
}
@@ -1,7 +1,7 @@
import type { ReactElement } from 'react';
import { useEffect, useState } from 'react';
import { Tooltip } from '../tooltip';
import CopyToClipboard from 'react-copy-to-clipboard';
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
export const TOOLTIP_TIMEOUT = 800;
@@ -11,22 +11,7 @@ export interface CopyWithTooltipProps {
}
export function CopyWithTooltip({ children, text }: CopyWithTooltipProps) {
const [copied, setCopied] = useState(false);
useEffect(() => {
// eslint-disable-next-line
let timeout: any;
if (copied) {
timeout = setTimeout(() => {
setCopied(false);
}, TOOLTIP_TIMEOUT);
}
return () => {
clearTimeout(timeout);
};
}, [copied]);
const [copied, setCopied] = useCopyTimeout();
return (
<CopyToClipboard text={text} onCopy={() => setCopied(true)}>
@@ -3,7 +3,7 @@ import * as DialogPrimitives from '@radix-ui/react-dialog';
import classNames from 'classnames';
import { getIntentBorder } from '../../utils/intent';
import { Icon } from '../icon';
import { VegaIcon, VegaIconNames } from '../icon';
import type { ReactNode } from 'react';
import type { Intent } from '../../utils/intent';
@@ -77,7 +77,7 @@ export function Dialog({
className="absolute p-2 top-0 right-0 md:top-2 md:right-2"
data-testid="dialog-close"
>
<Icon name="cross" />
<VegaIcon name={VegaIconNames.CROSS} />
</DialogPrimitives.Close>
)}
<div className="flex gap-4 max-w-full">
@@ -3,7 +3,6 @@ import classNames from 'classnames';
import type { ComponentProps, ReactNode } from 'react';
import { forwardRef } from 'react';
import { VegaIcon, VegaIconNames } from '../icon';
import { Icon } from '../icon';
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
import CopyToClipboard from 'react-copy-to-clipboard';
import { t } from '@vegaprotocol/i18n';
@@ -140,7 +139,7 @@ export const DropdownMenuItemIndicator = forwardRef<
ref={forwardedRef}
className="flex-end"
>
<Icon name="tick" />
<VegaIcon name={VegaIconNames.TICK} />
</DropdownMenuPrimitive.ItemIndicator>
));
@@ -25,14 +25,14 @@ const Target = ({
return (
<Tooltip
description={
<>
<div className="text-vega-dark-100 dark:text-vega-light-200">
<div className="mt-1.5 inline-flex">
<Indicator variant={Intent.None} />
</div>
<span>
{t('Target stake')} {addDecimalsFormatNumber(target, decimals)}
</span>
</>
</div>
}
>
<div
@@ -195,9 +195,11 @@ export const HealthBar = ({
{showRemainder && <Remainder />}
{showOverflow && (
<Tooltip
description={t(
'Providers greater than 2x target stake not shown'
)}
description={
<div className="text-vega-dark-100 dark:text-vega-light-200">
t( 'Providers greater than 2x target stake not shown' )
</div>
}
>
<div className="h-[inherit] relative flex-1 leading-4">...</div>
</Tooltip>
@@ -0,0 +1,7 @@
export const IconTick = ({ size = 16 }: { size: number }) => {
return (
<svg width={size} height={size} viewBox="0 0 16 16">
<path d="M6 11.2505L13.6252 3.62523L14.3748 4.37477L6 12.7495L1.62523 8.37477L2.37476 7.62523L6 11.2505Z" />
</svg>
);
};
@@ -18,6 +18,7 @@ import { IconCross } from './svg-icons/icon-cross';
import { IconKebab } from './svg-icons/icon-kebab';
import { IconArrowDown } from './svg-icons/icon-arrow-down';
import { IconChevronDown } from './svg-icons/icon-chevron-down';
import { IconTick } from './svg-icons/icon-tick';
export enum VegaIconNames {
BREAKDOWN = 'breakdown',
@@ -40,6 +41,7 @@ export enum VegaIconNames {
TREND_UP = 'trend-up',
CROSS = 'cross',
KEBAB = 'kebab',
TICK = 'tick',
}
export const VegaIconNameMap: Record<
@@ -66,4 +68,5 @@ export const VegaIconNameMap: Record<
'trend-up': IconTrendUp,
cross: IconCross,
kebab: IconKebab,
tick: IconTick,
};
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@vegaprotocol/utils",
"version": "0.0.5",
"version": "0.0.6",
"type": "commonjs"
}
@@ -3,7 +3,6 @@ import {
Button,
CopyWithTooltip,
Dialog,
Icon,
KeyValueTable,
KeyValueTableRow,
Splash,
@@ -32,7 +31,7 @@ export const WithdrawalApprovalDialog = ({
return (
<Dialog
title={t('Save withdrawal details')}
icon={<Icon name="info-sign"></Icon>}
icon={<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />}
open={open}
onChange={(isOpen) => onChange(isOpen)}
onCloseAutoFocus={(e) => {
+2 -4
View File
@@ -15,7 +15,6 @@ import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
Icon,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
@@ -193,9 +192,8 @@ export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
}
}}
>
<span>
<Icon name="info-sign" size={4} /> {t('View withdrawal details')}
</span>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View withdrawal details')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>