feat(deposits): if wrong network dont show the form and prompt switching to the correct network (#5571)

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
Bartłomiej Głownia 2024-01-18 10:41:19 +01:00 committed by GitHub
parent a2bffa1dfd
commit a8e6963521
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 77 additions and 66 deletions

View File

@ -1,10 +1,4 @@
import { import { waitFor, fireEvent, render, screen } from '@testing-library/react';
waitFor,
fireEvent,
render,
screen,
act,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import type { DepositFormProps } from './deposit-form'; import type { DepositFormProps } from './deposit-form';
@ -89,7 +83,10 @@ describe('Deposit form', () => {
render(<DepositForm {...props} />); render(<DepositForm {...props} />);
// Assert default values (including) from/to provided by useVegaWallet and useWeb3React // Assert default values (including) from/to provided by useVegaWallet and useWeb3React
expect(screen.getByText('From (Ethereum address)')).toBeInTheDocument(); // Wait for first value to show as form is rendered conditionally based on chainId
expect(
await screen.findByText('From (Ethereum address)')
).toBeInTheDocument();
expect(screen.getByTestId('ethereum-address')).toHaveTextContent( expect(screen.getByTestId('ethereum-address')).toHaveTextContent(
truncateMiddle(MOCK_ETH_ADDRESS) truncateMiddle(MOCK_ETH_ADDRESS)
); );
@ -319,34 +316,40 @@ describe('Deposit form', () => {
it('shows "View asset details" button when an asset is selected', async () => { it('shows "View asset details" button when an asset is selected', async () => {
render(<DepositForm {...props} selectedAsset={asset} />); render(<DepositForm {...props} selectedAsset={asset} />);
expect(await screen.getByTestId('view-asset-details')).toBeInTheDocument(); expect(await screen.findByTestId('view-asset-details')).toBeInTheDocument();
}); });
it('does not shows "View asset details" button when no asset is selected', async () => { it('does not shows "View asset details" button when no asset is selected', async () => {
render(<DepositForm {...props} />); render(<DepositForm {...props} />);
expect(await screen.queryAllByTestId('view-asset-details')).toHaveLength(0); await waitFor(() => {
expect(screen.queryAllByTestId('view-asset-details')).toHaveLength(0);
});
}); });
it('renders a connect button if Ethereum wallet is not connected', () => { it('renders a connect button if Ethereum wallet is not connected', async () => {
(useWeb3React as jest.Mock).mockReturnValue({ (useWeb3React as jest.Mock).mockReturnValue({
isActive: false, isActive: false,
account: '', account: '',
}); });
render(<DepositForm {...props} />); render(<DepositForm {...props} />);
expect(screen.getByRole('button', { name: 'Connect' })).toBeInTheDocument(); expect(
await screen.findByRole('button', { name: 'Connect' })
).toBeInTheDocument();
expect( expect(
screen.queryByLabelText('From (Ethereum address)') screen.queryByLabelText('From (Ethereum address)')
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
}); });
it('renders a disabled input if Ethereum wallet is connected', () => { it('renders a disabled input if Ethereum wallet is connected', async () => {
(useWeb3React as jest.Mock).mockReturnValue({ (useWeb3React as jest.Mock).mockReturnValue({
isActive: true, isActive: true,
account: MOCK_ETH_ADDRESS, account: MOCK_ETH_ADDRESS,
}); });
render(<DepositForm {...props} />); render(<DepositForm {...props} />);
expect(await screen.findByTestId('deposit-form')).toBeInTheDocument();
expect( expect(
screen.queryByRole('button', { name: 'Connect' }) screen.queryByRole('button', { name: 'Connect' })
).not.toBeInTheDocument(); ).not.toBeInTheDocument();
@ -356,53 +359,56 @@ describe('Deposit form', () => {
); );
}); });
it('prevents submission if you are on the wrong chain', () => { it('prevents submission if you are on the wrong chain', async () => {
// Make mocks return a chain id mismatch
(useWeb3React as jest.Mock).mockReturnValue({ (useWeb3React as jest.Mock).mockReturnValue({
isActive: true, isActive: true,
account: MOCK_ETH_ADDRESS, account: MOCK_ETH_ADDRESS,
chainId: 1, chainId: 1,
}); });
(useWeb3ConnectStore as unknown as jest.Mock).mockImplementation( (useWeb3ConnectStore as unknown as jest.Mock).mockImplementationOnce(
// eslint-disable-next-line // eslint-disable-next-line
(selector: (result: ReturnType<typeof useWeb3ConnectStore>) => any) => { (selector: (result: ReturnType<typeof useWeb3ConnectStore>) => any) => {
return selector({ return selector({
desiredChainId: 11155111, desiredChainId: 11155111,
open: jest.fn(), open: jest.fn(),
foo: 'asdf',
}); });
} }
); );
render(<DepositForm {...props} />); render(<DepositForm {...props} />);
expect(screen.getByTestId('chain-error')).toHaveTextContent(
expect(await screen.findByTestId('chain-error')).toHaveTextContent(
/this app only works on/i /this app only works on/i
); );
expect(screen.queryByTestId('deposit-form')).not.toBeInTheDocument();
}); });
it('Remaining deposit allowance tooltip should be rendered', async () => { it('Remaining deposit allowance tooltip should be rendered', async () => {
render(<DepositForm {...props} selectedAsset={asset} />); render(<DepositForm {...props} selectedAsset={asset} />);
await act(async () => {
await userEvent.hover(screen.getByText('Remaining deposit allowance')); expect(await screen.findByTestId('deposit-form')).toBeInTheDocument();
});
await waitFor(async () => { await userEvent.hover(screen.getByText('Remaining deposit allowance'));
await expect(
screen.getByRole('tooltip', { expect(
name: /VEGA has a lifetime deposit limit of 20 asset-symbol per address/, await screen.findByRole('tooltip', {
}) name: /VEGA has a lifetime deposit limit of 20 asset-symbol per address/,
).toBeInTheDocument(); })
}); ).toBeInTheDocument();
}); });
it('Ethereum deposit cap tooltip should be rendered', async () => { it('Ethereum deposit cap tooltip should be rendered', async () => {
render(<DepositForm {...props} selectedAsset={asset} />); render(<DepositForm {...props} selectedAsset={asset} />);
await act(async () => {
await userEvent.hover(screen.getByText('Ethereum deposit cap')); expect(await screen.findByTestId('deposit-form')).toBeInTheDocument();
});
await waitFor(async () => { await userEvent.hover(screen.getByText('Ethereum deposit cap'));
await expect(
screen.getByRole('tooltip', { expect(
name: /The deposit cap is set when you approve an asset for use with this app/, await screen.findByRole('tooltip', {
}) name: /The deposit cap is set when you approve an asset for use with this app/,
).toBeInTheDocument(); })
}); ).toBeInTheDocument();
}); });
}); });

View File

@ -92,7 +92,9 @@ export const DepositForm = ({
const maxSafe = useMaxSafe(); const maxSafe = useMaxSafe();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const openDialog = useWeb3ConnectStore((store) => store.open); const openDialog = useWeb3ConnectStore((store) => store.open);
const { isActive, account } = useWeb3React(); const { isActive, account, chainId } = useWeb3React();
const desiredChainId = useWeb3ConnectStore((store) => store.desiredChainId);
const invalidChain = isActive && chainId !== desiredChainId;
const { pubKey, pubKeys: _pubKeys } = useVegaWallet(); const { pubKey, pubKeys: _pubKeys } = useVegaWallet();
const [approveNotificationIntent, setApproveNotificationIntent] = const [approveNotificationIntent, setApproveNotificationIntent] =
useState<Intent>(Intent.Warning); useState<Intent>(Intent.Warning);
@ -152,7 +154,20 @@ export const DepositForm = ({
const approved = const approved =
balances && balances.allowance.isGreaterThan(0) ? true : false; balances && balances.allowance.isGreaterThan(0) ? true : false;
return ( return invalidChain ? (
<div className="mb-2">
<Notification
intent={Intent.Danger}
testId="chain-error"
message={t(
'This app only works on {{chainId}}. Switch your Ethereum wallet to the correct network.',
{
chainId: getChainName(desiredChainId),
}
)}
/>
</div>
) : (
<form <form
onSubmit={handleSubmit(onSubmit)} onSubmit={handleSubmit(onSubmit)}
noValidate={true} noValidate={true}
@ -417,7 +432,11 @@ export const DepositForm = ({
intent={approveNotificationIntent} intent={approveNotificationIntent}
amount={amount} amount={amount}
/> />
<FormButton approved={approved} selectedAsset={selectedAsset} /> <FormButton
approved={approved}
isActive={isActive}
selectedAsset={selectedAsset}
/>
</form> </form>
); );
}; };
@ -425,35 +444,21 @@ export const DepositForm = ({
interface FormButtonProps { interface FormButtonProps {
approved: boolean; approved: boolean;
selectedAsset: AssetFieldsFragment | undefined; selectedAsset: AssetFieldsFragment | undefined;
isActive: boolean;
} }
const FormButton = ({ approved, selectedAsset }: FormButtonProps) => { const FormButton = ({ approved, selectedAsset, isActive }: FormButtonProps) => {
const t = useT(); const t = useT();
const { isActive, chainId } = useWeb3React();
const desiredChainId = useWeb3ConnectStore((store) => store.desiredChainId);
const invalidChain = isActive && chainId !== desiredChainId;
return ( return (
<> <TradingButton
{invalidChain && ( type="submit"
<div className="mb-2"> data-testid="deposit-submit"
<Notification fill
intent={Intent.Danger} disabled={!isActive}
testId="chain-error" >
message={t('This app only works on {{chainId}}.', { {t('Deposit')}
chainId: getChainName(desiredChainId), </TradingButton>
})}
/>
</div>
)}
<TradingButton
type="submit"
data-testid="deposit-submit"
fill
disabled={!isActive || invalidChain}
>
{t('Deposit')}
</TradingButton>
</>
); );
}; };

View File

@ -27,7 +27,7 @@
"The {{symbol}} faucet is not available at this time": "The {{symbol}} faucet is not available at this time", "The {{symbol}} faucet is not available at this time": "The {{symbol}} faucet is not available at this time",
"The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.": "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.", "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.": "The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve {{assetSymbol}} again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.",
"The faucet transaction was rejected by the connected Ethereum wallet": "The faucet transaction was rejected by the connected Ethereum wallet", "The faucet transaction was rejected by the connected Ethereum wallet": "The faucet transaction was rejected by the connected Ethereum wallet",
"This app only works on {{chainId}}.": "This app only works on {{chainId}}.", "This app only works on {{chainId}}. Switch your Ethereum wallet to the correct network.": "This app only works on {{chainId}}. Switch your Ethereum wallet to the correct network.",
"To (Vega key)": "To (Vega key)", "To (Vega key)": "To (Vega key)",
"To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.": "To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.", "To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.": "To date, {{currentDeposit}} {{assetSymbol}} has been deposited from this Ethereum address, so you can deposit up to {{remainingDeposit}} {{assetSymbol}} more.",
"Use maximum": "Use maximum", "Use maximum": "Use maximum",