Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WALL] aum / WALL-3863 / wallet-withdrawal-blocked-on-zero-balance #14906

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useEffect, useState } from 'react';
import { useActiveWalletAccount, useAuthorize, useCurrencyConfig } from '@deriv/api-v2';
import { useActiveWalletAccount, useAuthorize } from '@deriv/api-v2';
import { Loader } from '../../../../components';
import { WithdrawalCryptoModule, WithdrawalFiatModule, WithdrawalVerificationModule } from '../../modules';
import { WithdrawalNoBalance } from '../../screens';

const WalletWithdrawal = () => {
const { isSuccess: isCurrencyConfigSuccess } = useCurrencyConfig();
const { switchAccount } = useAuthorize();
const { data: activeWallet } = useActiveWalletAccount();
const [verificationCode, setVerificationCode] = useState('');
Expand Down Expand Up @@ -33,20 +33,21 @@ const WalletWithdrawal = () => {

const isCrypto = activeWallet?.currency_config?.is_crypto;

if (verificationCode) {
if (isCurrencyConfigSuccess && activeWallet?.currency) {
return isCrypto ? (
<WithdrawalCryptoModule
onClose={() => {
setVerificationCode('');
}}
verificationCode={verificationCode}
/>
) : (
<WithdrawalFiatModule verificationCode={verificationCode} />
);
}
return <Loader />;
if (!activeWallet) return <Loader />;

if (activeWallet.balance <= 0) return <WithdrawalNoBalance activeWallet={activeWallet} />;

if (activeWallet?.currency && verificationCode) {
return isCrypto ? (
<WithdrawalCryptoModule
onClose={() => {
setVerificationCode('');
}}
verificationCode={verificationCode}
/>
) : (
<WithdrawalFiatModule verificationCode={verificationCode} />
);
}

return <WithdrawalVerificationModule />;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { PropsWithChildren } from 'react';
import { useActiveWalletAccount, useCurrencyConfig } from '@deriv/api-v2';
import { useActiveWalletAccount } from '@deriv/api-v2';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { CashierLocked, WithdrawalLocked } from '../../../modules';
import WalletWithdrawal from '../WalletWithdrawal';
Expand Down Expand Up @@ -27,6 +27,11 @@ jest.mock('../../../modules', () => ({
WithdrawalVerificationModule: jest.fn(() => <div>WithdrawalVerificationModule</div>),
}));

jest.mock('../../../screens', () => ({
...jest.requireActual('../../../screens'),
WithdrawalNoBalance: jest.fn(() => <div>WithdrawalNoBalance</div>),
}));

jest.mock('../../../../../components', () => ({
...jest.requireActual('../../../../../components'),
Loader: jest.fn(() => <div>Loading</div>),
Expand All @@ -36,13 +41,10 @@ jest.mock('@deriv/api-v2', () => ({
...jest.requireActual('@deriv/api-v2'),
useActiveWalletAccount: jest.fn(),
useAuthorize: jest.fn(() => ({ switchAccount: jest.fn() })),
useCurrencyConfig: jest.fn(),
}));

const mockUseActiveWalletAccount = useActiveWalletAccount as jest.MockedFunction<typeof useActiveWalletAccount>;

const mockUseCurrencyConfig = useCurrencyConfig as jest.MockedFunction<typeof useCurrencyConfig>;

const wrapper = ({ children }: PropsWithChildren) => (
<CashierLocked>
<WithdrawalLocked>{children}</WithdrawalLocked>
Expand Down Expand Up @@ -71,17 +73,13 @@ describe('WalletWithdrawal', () => {
mockUseActiveWalletAccount.mockReturnValue({
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
data: {
balance: 100,

currency: 'USD',
loginid: 'CR42069',
},
});

// @ts-expect-error - since this is a mock, we only need partial properties of the hook
mockUseCurrencyConfig.mockReturnValue({
getConfig: jest.fn(),
isSuccess: true,
});

render(<WalletWithdrawal />, { wrapper });

expect(replaceStateSpy).toBeCalledWith({}, '', 'http://localhost/redirect');
Expand All @@ -96,17 +94,12 @@ describe('WalletWithdrawal', () => {
mockUseActiveWalletAccount.mockReturnValue({
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
data: {
balance: 100,
currency: 'USD',
loginid: 'CR42069',
},
});

// @ts-expect-error - since this is a mock, we only need partial properties of the hook
mockUseCurrencyConfig.mockReturnValue({
getConfig: jest.fn(),
isSuccess: true,
});

render(<WalletWithdrawal />, { wrapper });
expect(screen.getByText('WithdrawalVerificationModule')).toBeInTheDocument();
});
Expand All @@ -115,17 +108,13 @@ describe('WalletWithdrawal', () => {
mockUseActiveWalletAccount.mockReturnValue({
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
data: {
balance: 100,

currency: 'USD',
loginid: 'CR42069',
},
});

mockUseCurrencyConfig.mockReturnValue({
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
getConfig: jest.fn(() => ({ is_fiat: true })),
isSuccess: true,
});

render(<WalletWithdrawal />, { wrapper });
expect(screen.getByText('WithdrawalFiatModule')).toBeInTheDocument();
expect(screen.getByText('verificationCode=1234')).toBeInTheDocument();
Expand All @@ -134,20 +123,14 @@ describe('WalletWithdrawal', () => {
it('should render withdrawal crypto module if withdrawal is for crypto wallet', async () => {
mockUseActiveWalletAccount.mockReturnValue({
data: {
balance: 100,
currency: 'BTC',
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
currency_config: { is_crypto: true },
loginid: 'CR42069',
},
});

mockUseCurrencyConfig.mockReturnValue(
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
{
isSuccess: true,
}
);

render(<WalletWithdrawal />, { wrapper });
expect(screen.getByText('WithdrawalCryptoModule')).toBeInTheDocument();
expect(screen.getByText('verificationCode=1234')).toBeInTheDocument();
Expand All @@ -156,20 +139,15 @@ describe('WalletWithdrawal', () => {
it('should render withdrawal email verification module when onClose is triggered on the withdrawal crypto module', async () => {
mockUseActiveWalletAccount.mockReturnValue({
data: {
balance: 100,

currency: 'BTC',
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
currency_config: { is_crypto: true },
loginid: 'CR42069',
},
});

mockUseCurrencyConfig.mockReturnValue(
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
{
isSuccess: true,
}
);

render(<WalletWithdrawal />, { wrapper });
await waitFor(() => {
const button = screen.getByRole('button');
Expand All @@ -179,22 +157,25 @@ describe('WalletWithdrawal', () => {
});
});

it('should show loader if verification code is there but currency config is yet to be loaded', () => {
it('should show loader if verification code is activeWallet data has not been received yet', () => {
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
mockUseActiveWalletAccount.mockReturnValue({});

render(<WalletWithdrawal />, { wrapper });
expect(screen.getByText('Loading')).toBeInTheDocument();
});

it('should test if WithdrawalNoBalance screen is rendered if the wallet balance has zero balance', () => {
mockUseActiveWalletAccount.mockReturnValue({
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
data: {
balance: 0,
currency: 'BTC',
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
currency_config: { is_crypto: true },
loginid: 'CR42069',
},
});

// @ts-expect-error - since this is a mock, we only need partial properties of the hook
mockUseCurrencyConfig.mockReturnValue({
getConfig: jest.fn(),
isSuccess: false,
});

render(<WalletWithdrawal />, { wrapper });
expect(screen.getByText('Loading')).toBeInTheDocument();
expect(screen.getByText('WithdrawalNoBalance')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const WithdrawalVerificationRequest: React.FC<TProps> = ({ sendEmail }) => {
description={
<div className='wallets-withdrawal-verification-request__description'>
<WalletText align='center'>
Hit the button below, and we&apos;ll email you a verification link.
Press the button below, and we&apos;ll email you a verification link.
</WalletText>
<WalletText align='center'>
This is to confirm that it&apos;s you making the withdrawal request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ describe('WithdrawalVerificationRequest', () => {
test('should render component correctly', () => {
render(<WithdrawalVerificationRequest sendEmail={jest.fn()} />);

expect(screen.getByText("Hit the button below, and we'll email you a verification link.")).toBeInTheDocument();
expect(
screen.getByText("Press the button below, and we'll email you a verification link.")
).toBeInTheDocument();

const sendEmailButton = screen.getByRole('button', { name: 'Send email' });
expect(sendEmailButton).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ jest.mock('@deriv/api-v2', () => ({
describe('WithdrawalVerification', () => {
it('should render WithdrawalVerificationRequest initially', () => {
render(<WithdrawalVerification />);
expect(screen.getByText("Hit the button below, and we'll email you a verification link.")).toBeInTheDocument();
expect(
screen.getByText("Press the button below, and we'll email you a verification link.")
).toBeInTheDocument();
});

it('should send withdrawal verification email and render WithdrawalVerificationSent after clicking send email', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { DerivLightCashierNoBalanceIcon } from '@deriv/quill-icons';
import { WalletButton, WalletsActionScreen } from '../../../../components';
import { THooks } from '../../../../types';

type TWithdrawalNoBalanceProps = {
activeWallet: THooks.ActiveWalletAccount;
};

const WithdrawalNoBalance: React.FC<TWithdrawalNoBalanceProps> = ({ activeWallet }) => {
const history = useHistory();

return (
<WalletsActionScreen
description={`You don't have funds in your ${activeWallet.currency} Wallet to complete a withdrawal.`}
descriptionSize='md'
icon={<DerivLightCashierNoBalanceIcon height='128px' width='128px' />}
renderButtons={() => (
<WalletButton onClick={() => history.push('/wallets/cashier/deposit')} size='lg'>
Add funds
</WalletButton>
)}
title={`No funds in ${activeWallet.currency} Wallet`}
/>
);
};

export default WithdrawalNoBalance;
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { render, screen, within } from '@testing-library/react';
import WithdrawalNoBalance from '../WithdrawalNoBalance';

jest.mock('@deriv/quill-icons', () => ({
...jest.requireActual('@deriv/quill-icons'),
DerivLightCashierNoBalanceIcon: jest.fn(({ height, width }) => (
<span>
DerivLightCashierNoBalanceIcon-{height}/{width}
</span>
)),
}));

jest.mock('../../../../../components', () => ({
...jest.requireActual('../../../../../components'),
WalletsActionScreen: jest.fn(({ description, descriptionSize, icon, renderButtons, title }) => (
<div>
<div>{icon}</div>
<span>
WalletsActionScreen-{title}/{description}/{descriptionSize}
</span>
<div>{renderButtons()}</div>
</div>
)),
}));

const mockActiveWallet = {
balance: 0,
currency: 'USD',
};

describe('WithdrawalNoBalance', () => {
it('should test whether WalletsActionScreen is rendered with correct props', () => {
render(
// @ts-expect-error - since this is a mock, we only need partial properties of the hook
<WithdrawalNoBalance activeWallet={mockActiveWallet} />
);

expect(
screen.getByText(
`WalletsActionScreen-No funds in USD Wallet/You don't have funds in your USD Wallet to complete a withdrawal./md`
)
).toBeInTheDocument();

expect(screen.getByText('DerivLightCashierNoBalanceIcon-128px/128px')).toBeInTheDocument();
expect(within(screen.getByRole('button')).getByText('Add funds')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as WithdrawalNoBalance } from './WithdrawalNoBalance';
1 change: 1 addition & 0 deletions packages/wallets/src/features/cashier/screens/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './TransferNotAvailable';
export * from './WithdrawalNoBalance';
Loading