Feat/800: Improved tests for the proposal forms

This commit is contained in:
sam-keen
2022-09-13 16:58:07 +01:00
parent e67f322400
commit 4f8a585956
10 changed files with 565 additions and 166 deletions
@@ -1,18 +1,77 @@
import { render } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { ProposeFreeform } from './propose-freeform';
import { NetworkLoader } from '@vegaprotocol/environment';
import { createClient } from '../../../../lib/apollo-client';
import { MockedProvider } from '@apollo/client/testing';
import {
mockWalletContext,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { BrowserRouter as Router } from 'react-router-dom';
jest.mock('../../../../hooks/use-network-param.tsx', () => ({
useNetworkParamWithKeys: () => ({
data: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.maxClose',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.maxEnact',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.minClose',
value: '1h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.minEnact',
value: '2h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.freeform.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.freeform.min.tokens',
value: '1000000000000000000',
},
],
loading: false,
error: undefined,
}),
}));
const renderComponent = () =>
render(
<NetworkLoader createClient={createClient}>
<ProposeFreeform />
</NetworkLoader>
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeFreeform />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
describe('ProposeFreeform', () => {
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Freeform', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should render the title', () => {
renderComponent();
expect(screen.getByText('New freeform proposal')).toBeTruthy();
});
});
@@ -1,37 +1,115 @@
import { render } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';
import { ProposeNetworkParameter } from './propose-network-parameter';
import { NetworkLoader } from '@vegaprotocol/environment';
import { createClient } from '../../../../lib/apollo-client';
import { MockedProvider } from '@apollo/client/testing';
import {
mockWalletContext,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { BrowserRouter as Router } from 'react-router-dom';
jest.mock('../../../../hooks/use-network-param.tsx', () => ({
useNetworkParamWithKeys: () => ({
data: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.maxClose',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.maxEnact',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.minClose',
value: '1h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.minEnact',
value: '2h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateNetParam.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.proposal.min.tokens',
value: '1000000000000000000',
},
{
key: 'limits.assets.proposeEnabledFrom',
value: '',
},
{
key: 'limits.markets.proposeEnabledFrom',
value: '',
},
{
key: 'market.auction.maximumDuration',
value: '168h0m0s',
},
],
loading: false,
error: undefined,
}),
}));
const renderComponent = () =>
render(
<NetworkLoader createClient={createClient}>
<ProposeNetworkParameter />
</NetworkLoader>
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNetworkParameter />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
// const mockNetworkParams = [
// {
// key: 'governance.proposal.updateNetParam.requiredParticipation',
// value: '0.3',
// },
// {
// key: 'limits.assets.proposeEnabledFrom',
// value: '',
// },
// {
// key: 'limits.markets.proposeEnabledFrom',
// value: '',
// },
// {
// key: 'market.auction.maximumDuration',
// value: '168h0m0s',
// },
// ];
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('ProposeNetworkParameter', () => {
describe('Propose Network Parameter', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should render the correct title', () => {
renderComponent();
expect(screen.getByText('Update network parameter proposal')).toBeTruthy();
});
it('should render the network param select element with no initial value', () => {
renderComponent();
expect(screen.getByTestId('proposal-parameter-select')).toHaveValue('');
});
it('should render the current param value and a new value input when the network param select element is changed', () => {
renderComponent();
const select = screen.getByTestId('proposal-parameter-select');
expect(select).toHaveValue('');
fireEvent.change(screen.getByTestId('proposal-parameter-select'), {
target: {
value: 'spam.protection.proposal.min.tokens',
},
});
expect(select).toHaveValue('spam.protection.proposal.min.tokens');
expect(
screen.getByTestId('selected-proposal-param-current-value')
).toHaveValue('1000000000000000000');
expect(
screen.getByTestId('selected-proposal-param-new-value')
).toBeVisible();
});
});
@@ -45,10 +45,15 @@ const SelectedNetworkParamCurrentValue = ({
return (
<div className="mb-4">
<p className="text-sm text-white">{t('CurrentValue')}</p>
{isJsonObject(value) ? (
<SyntaxHighlighter data={JSON.parse(value)} />
) : (
<Input value={value} readOnly />
<Input
value={value}
data-testid="selected-proposal-param-current-value"
readOnly
/>
)}
</div>
);
@@ -193,6 +198,7 @@ export const ProposeNetworkParameter = () => {
hideLabel={true}
>
<Select
data-testid="proposal-parameter-select"
id="proposal-parameter-key"
{...register('proposalNetworkParameterKey', {
required: t('Required'),
@@ -226,10 +232,11 @@ export const ProposeNetworkParameter = () => {
<FormGroup
label={t('NewProposedValue')}
labelFor="proposal-parameter-value"
labelFor="proposal-parameter-new-value"
>
<TextArea
id="proposal-parameter-value"
data-testid="selected-proposal-param-new-value"
id="proposal-parameter-new-value"
{...register('proposalNetworkParameterValue', {
required: t('Required'),
})}
@@ -1,18 +1,77 @@
import { render } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { BrowserRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import {
mockWalletContext,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { ProposeNewAsset } from './propose-new-asset';
import { NetworkLoader } from '@vegaprotocol/environment';
import { createClient } from '../../../../lib/apollo-client';
jest.mock('../../../../hooks/use-network-param.tsx', () => ({
useNetworkParamWithKeys: () => ({
data: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.maxClose',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.maxEnact',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.minClose',
value: '1h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.minEnact',
value: '2h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.asset.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.proposal.min.tokens',
value: '1000000000000000000',
},
],
loading: false,
error: undefined,
}),
}));
const renderComponent = () =>
render(
<NetworkLoader createClient={createClient}>
<ProposeNewAsset />
</NetworkLoader>
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNewAsset />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
describe('ProposeNewAsset', () => {
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose New Asset', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should render the title', () => {
renderComponent();
expect(screen.getByText('New asset proposal')).toBeTruthy();
});
});
@@ -5,6 +5,7 @@ import {
useProposalSubmit,
getClosingTimestamp,
getEnactmentTimestamp,
getValidationTimestamp,
} from '@vegaprotocol/governance';
import { useEnvironment } from '@vegaprotocol/environment';
import {
@@ -27,6 +28,7 @@ import type { ProposalNewAssetTerms } from '@vegaprotocol/wallet';
export interface NewAssetProposalFormFields {
proposalVoteDeadline: number;
proposalEnactmentDeadline: number;
proposalValidationDeadline: number;
proposalTitle: string;
proposalDescription: string;
proposalTerms: string;
@@ -102,6 +104,9 @@ export const ProposeNewAsset = () => {
fields.proposalVoteDeadline,
fields.proposalEnactmentDeadline
),
validationTimestamp: getValidationTimestamp(
fields.proposalValidationDeadline
),
} as ProposalNewAssetTerms,
});
};
@@ -185,6 +190,13 @@ export const ProposeNewAsset = () => {
}
enactmentMinClose={minEnactmentDeadline as string}
enactmentMaxClose={maxEnactmentDeadline as string}
validationRequired={true}
validationRegister={register('proposalValidationDeadline', {
required: t('Required'),
})}
validationErrorMessage={
errors?.proposalValidationDeadline?.message
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
@@ -1,15 +1,30 @@
import { render } from '@testing-library/react';
import { ProposeNewMarket } from './propose-new-market';
import { NetworkLoader } from '@vegaprotocol/environment';
import { createClient } from '../../../../lib/apollo-client';
import { MockedProvider } from '@apollo/client/testing';
import {
mockWalletContext,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { BrowserRouter as Router } from 'react-router-dom';
const renderComponent = () =>
render(
<NetworkLoader createClient={createClient}>
<ProposeNewMarket />
</NetworkLoader>
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeNewMarket />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('ProposeNewMarket', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
@@ -167,6 +167,7 @@ export const ProposeNewMarket = () => {
},
},
})}
labelOverride={'Terms.changes.newMarket (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
/>
@@ -1,5 +1,6 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import type { MockedResponse } from '@apollo/client/testing';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet';
@@ -44,18 +45,20 @@ describe('Raw proposal form', () => {
};
const setup = (mockSendTx = jest.fn()) => {
return render(
<MockedProvider mocks={[mockProposalEvent]}>
<VegaWalletContext.Provider
value={
{
keypair: { pub: pubkey },
sendTx: mockSendTx,
} as unknown as VegaWalletContextShape
}
>
<ProposeRaw />
</VegaWalletContext.Provider>
</MockedProvider>
<AppStateProvider>
<MockedProvider mocks={[mockProposalEvent]}>
<VegaWalletContext.Provider
value={
{
keypair: { pub: pubkey },
sendTx: mockSendTx,
} as unknown as VegaWalletContextShape
}
>
<ProposeRaw />
</VegaWalletContext.Provider>
</MockedProvider>
</AppStateProvider>
);
};
@@ -67,7 +70,7 @@ describe('Raw proposal form', () => {
jest.useRealTimers();
});
it.skip('handles validation', async () => {
it('handles validation', async () => {
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve());
setup(mockSendTx);
await act(async () => {
@@ -93,102 +96,102 @@ describe('Raw proposal form', () => {
);
});
// it('sends the transaction', async () => {
// const mockSendTx = jest.fn().mockReturnValue(
// new Promise((resolve) => {
// setTimeout(
// () =>
// resolve({
// txHash: 'tx-hash',
// tx: {
// signature: {
// value:
// 'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
// },
// },
// }),
// 100
// );
// })
// );
// setup(mockSendTx);
//
// const inputJSON = JSON.stringify({
// rationale: {
// description: 'Update governance.proposal.freeform.minVoterBalance',
// title: 'testing 123',
// },
// terms: {
// updateNetworkParameter: {
// changes: {
// key: 'governance.proposal.freeform.minVoterBalance',
// value: '300',
// },
// },
// closingTimestamp: 1657721401,
// enactmentTimestamp: 1657807801,
// },
// });
// fireEvent.change(screen.getByTestId('proposal-data'), {
// target: { value: inputJSON },
// });
//
// await act(async () => {
// fireEvent.click(screen.getByTestId('proposal-submit'));
// });
//
// expect(mockSendTx).toHaveBeenCalledWith({
// propagate: true,
// pubKey: pubkey,
// proposalSubmission: JSON.parse(inputJSON),
// });
//
// expect(screen.getByTestId('dialog-title')).toHaveTextContent(
// 'Confirm transaction in wallet'
// );
//
// await act(async () => {
// jest.advanceTimersByTime(200);
// });
//
// expect(screen.getByTestId('dialog-title')).toHaveTextContent(
// 'Awaiting network confirmation'
// );
//
// await act(async () => {
// jest.advanceTimersByTime(400);
// });
//
// expect(screen.getByTestId('dialog-title')).toHaveTextContent(
// 'Proposal rejected'
// );
// });
//
// it('can be rejected by the user', async () => {
// const mockSendTx = jest.fn().mockReturnValue(
// new Promise((resolve) => {
// setTimeout(() => resolve(null), 100);
// })
// );
// setup(mockSendTx);
//
// const inputJSON = '{}';
// fireEvent.change(screen.getByTestId('proposal-data'), {
// target: { value: inputJSON },
// });
//
// await act(async () => {
// fireEvent.click(screen.getByTestId('proposal-submit'));
// });
//
// expect(screen.getByTestId('dialog-title')).toHaveTextContent(
// 'Confirm transaction in wallet'
// );
//
// await act(async () => {
// jest.advanceTimersByTime(200);
// });
//
// expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
// });
it('sends the transaction', async () => {
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(
() =>
resolve({
txHash: 'tx-hash',
tx: {
signature: {
value:
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
},
},
}),
100
);
})
);
setup(mockSendTx);
const inputJSON = JSON.stringify({
rationale: {
description: 'Update governance.proposal.freeform.minVoterBalance',
title: 'testing 123',
},
terms: {
updateNetworkParameter: {
changes: {
key: 'governance.proposal.freeform.minVoterBalance',
value: '300',
},
},
closingTimestamp: 1657721401,
enactmentTimestamp: 1657807801,
},
});
fireEvent.change(screen.getByTestId('proposal-data'), {
target: { value: inputJSON },
});
await act(async () => {
fireEvent.click(screen.getByTestId('proposal-submit'));
});
expect(mockSendTx).toHaveBeenCalledWith({
propagate: true,
pubKey: pubkey,
proposalSubmission: JSON.parse(inputJSON),
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
'Confirm transaction in wallet'
);
await act(async () => {
jest.advanceTimersByTime(200);
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
'Awaiting network confirmation'
);
await act(async () => {
jest.advanceTimersByTime(400);
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
'Proposal rejected'
);
});
it('can be rejected by the user', async () => {
const mockSendTx = jest.fn().mockReturnValue(
new Promise((resolve) => {
setTimeout(() => resolve(null), 100);
})
);
setup(mockSendTx);
const inputJSON = '{}';
fireEvent.change(screen.getByTestId('proposal-data'), {
target: { value: inputJSON },
});
await act(async () => {
fireEvent.click(screen.getByTestId('proposal-submit'));
});
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
'Confirm transaction in wallet'
);
await act(async () => {
jest.advanceTimersByTime(200);
});
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
@@ -1,18 +1,182 @@
import { render } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { BrowserRouter as Router } from 'react-router-dom';
import { render, screen, fireEvent } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import {
mockWalletContext,
networkParamsQueryMock,
} from '../../test-helpers/mocks';
import { ProposeUpdateMarket } from './propose-update-market';
import { NetworkLoader } from '@vegaprotocol/environment';
import { createClient } from '../../../../lib/apollo-client';
jest.mock('../../../../hooks/use-network-param.tsx', () => ({
useNetworkParamWithKeys: () => ({
data: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.maxClose',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.maxEnact',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.minClose',
value: '1h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.minEnact',
value: '2h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateMarket.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.proposal.min.tokens',
value: '1000000000000000000',
},
],
loading: false,
error: undefined,
}),
}));
jest.mock('@apollo/client', () => ({
...jest.requireActual('@apollo/client'),
useQuery: jest.fn(() => ({
data: {
marketsConnection: {
__typename: 'MarketConnection',
edges: [
{
__typename: 'MarketEdge',
node: {
__typename: 'Market',
id: 'd2319c91104a523032cf04ac4e20962b87ee1f187d1e411a2cac12554dd38f29',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'ETHUSD (September Market)',
code: 'ETHiUSDT',
},
},
},
},
{
__typename: 'MarketEdge',
node: {
__typename: 'Market',
id: 'bb941f84e25b3a06068e33917d01215d56a51e9abff6ff9b9a3f2cf49b495e37',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'Las Vegas nuggets',
code: 'Nuggets2',
},
},
},
},
{
__typename: 'MarketEdge',
node: {
__typename: 'Market',
id: '976f71b8d6f99f3685297156a11245f21e49c99d3be17f2577a4bf693b5f37d1',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'Nuggets',
code: 'Nuggets',
},
},
},
},
{
__typename: 'MarketEdge',
node: {
__typename: 'Market',
id: '1cb2e1755208914b6f258a28babd19ae8dfbaf4084d8867d8a120c50dca1e17f',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'CELUSD (June 2022)',
code: 'CELUSD',
},
},
},
},
],
},
},
loading: false,
error: undefined,
})),
}));
const renderComponent = () =>
render(
<NetworkLoader createClient={createClient}>
<ProposeUpdateMarket />
</NetworkLoader>
<Router>
<MockedProvider mocks={[networkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeUpdateMarket />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
describe('ProposeUpdateMarket', () => {
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Update Market', () => {
it('should render successfully', () => {
const { baseElement } = renderComponent();
expect(baseElement).toBeTruthy();
});
it('should render the title', () => {
renderComponent();
expect(screen.getByText('Update market proposal')).toBeTruthy();
});
it('should render the select element with no initial value', () => {
renderComponent();
expect(screen.getByTestId('proposal-market-select')).toHaveValue('');
});
it('should render the correct market details when the market select is used', () => {
renderComponent();
fireEvent.change(screen.getByTestId('proposal-market-select'), {
target: {
value:
'd2319c91104a523032cf04ac4e20962b87ee1f187d1e411a2cac12554dd38f29',
},
});
expect(screen.getByTestId('proposal-market-select')).toHaveValue(
'd2319c91104a523032cf04ac4e20962b87ee1f187d1e411a2cac12554dd38f29'
);
expect(screen.getByTestId('update-market-details')).toHaveTextContent(
'ETHUSD (September Market)'
);
expect(screen.getByTestId('update-market-details')).toHaveTextContent(
'ETHiUSDT'
);
expect(screen.getByTestId('update-market-details')).toHaveTextContent(
'd2319c91104a523032cf04ac4e20962b87ee1f187d1e411a2cac12554dd38f29'
);
});
});
@@ -225,6 +225,7 @@ export const ProposeUpdateMarket = () => {
hideLabel={true}
>
<Select
data-testid="proposal-market-select"
id="proposal-market"
{...register('proposalMarketId', {
required: t('Required'),
@@ -286,7 +287,7 @@ export const ProposeUpdateMarket = () => {
},
},
})}
labelOverride={t('ProposeUpdateMarketChanges')}
labelOverride={t('ProposeUpdateMarketTerms')}
errorMessage={errors?.proposalTerms?.message}
/>