Skip to content

Commit a8186b0

Browse files
authored
Merge 024e3d8 into 94644cd
2 parents 94644cd + 024e3d8 commit a8186b0

36 files changed

+1828
-128
lines changed

packages/core/jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module.exports = {
44
...baseConfigForPackages,
55
moduleNameMapper: {
66
'\\.s(c|a)ss$': '<rootDir>/../../__mocks__/styleMock.js',
7+
'\\.css$': '<rootDir>/../../__mocks__/styleMock.js',
78
'^.+\\.svg$': '<rootDir>/../../__mocks__/styleMock.js',
89
'@deriv-com/translations': '<rootDir>/../../__mocks__/translation.mock.js',
910
'^_common/(.*)$': '<rootDir>/src/_common/$1',
@@ -18,4 +19,5 @@ module.exports = {
1819
'^Services$': '<rootDir>/src/Services/index.js',
1920
'^Stores/(.*)$': '<rootDir>/src/Stores/$1',
2021
},
22+
transformIgnorePatterns: ['/node_modules/(?!(@deriv-com/quill-ui|@simplewebauthn/browser)).+\\.js$'],
2123
};

packages/core/src/App/Components/Layout/Header/account-info-wrapper.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@ import { isBot } from '@deriv/shared';
55
type TAccountInfoWrapper = {
66
is_disabled?: boolean;
77
is_mobile?: boolean;
8+
is_dtrader_v2?: boolean;
89
disabled_message?: string;
910
};
1011

1112
const AccountInfoWrapper = ({
1213
is_disabled,
1314
is_mobile,
15+
is_dtrader_v2,
1416
disabled_message,
1517
children,
1618
}: React.PropsWithChildren<TAccountInfoWrapper>) =>
1719
is_disabled && disabled_message ? (
18-
<Popover alignment={isBot() && is_mobile ? 'bottom' : 'left'} message={disabled_message} zIndex='99999'>
20+
<Popover
21+
alignment={(isBot() || is_dtrader_v2) && is_mobile ? 'bottom' : 'left'}
22+
message={disabled_message}
23+
zIndex='99999'
24+
>
1925
{children}
2026
</Popover>
2127
) : (
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import { getAccountTitle, getAccountIcon } from '../account-switcher-dtrader-v2-utils';
4+
5+
const mock_currency_none_icon = 'CurrencyNoneIcon';
6+
const mock_currency_demo_icon = 'CurrencyDemoIcon';
7+
const mock_currency_usd_icon = 'CurrencyUsdIcon';
8+
9+
jest.mock('@deriv/quill-icons', () => ({
10+
...jest.requireActual('@deriv/quill-icons'),
11+
CurrencyNoneIcon: jest.fn(() => mock_currency_none_icon),
12+
CurrencyDemoIcon: jest.fn(() => mock_currency_demo_icon),
13+
CurrencyUsdIcon: jest.fn(() => mock_currency_usd_icon),
14+
}));
15+
16+
describe('getAccountTitle', () => {
17+
const mock_args = {
18+
currency: '',
19+
loginid: 'VRTC90000884',
20+
is_virtual: false,
21+
show_no_currency: true,
22+
};
23+
24+
it('should return "Multipliers" if loginid contains MF', () => {
25+
render(getAccountTitle({ ...mock_args, loginid: 'MF90000884' }));
26+
27+
expect(screen.getByText('Multipliers')).toBeInTheDocument();
28+
});
29+
30+
it('should return "Demo" if loginid does not contain MF and is_virtual === true', () => {
31+
render(getAccountTitle({ ...mock_args, is_virtual: true }));
32+
33+
expect(screen.getByText('Demo')).toBeInTheDocument();
34+
});
35+
36+
it('should return "No currency assigned" if loginid does not contain MF, is_virtual and currency are falsy and show_no_currency is true', () => {
37+
render(getAccountTitle(mock_args));
38+
39+
expect(screen.getByText('No currency assigned')).toBeInTheDocument();
40+
});
41+
42+
it('should return users loginid if loginid does not contain MF, is_virtual and currency are falsy and show_no_currency is false', () => {
43+
expect(getAccountTitle({ ...mock_args, show_no_currency: false })).toBe('VRTC90000884');
44+
});
45+
46+
it('should return currency name if loginid does not contain MF, is_virtual and show_no_currency are falsy and there is currency', () => {
47+
expect(getAccountTitle({ ...mock_args, currency: 'USDT' })).toBe('Tether Omni');
48+
});
49+
});
50+
51+
describe('getAccountIcon', () => {
52+
const mock_args: Parameters<typeof getAccountIcon>[0] = {
53+
currency: 'USD',
54+
is_virtual: false,
55+
size: 'sm',
56+
};
57+
58+
it('should return CurrencyDemoIcon icon if is_virtual === true', () => {
59+
render(getAccountIcon({ ...mock_args, is_virtual: true }));
60+
61+
expect(screen.getByText(mock_currency_demo_icon)).toBeInTheDocument();
62+
});
63+
64+
it('should return CurrencyNoneIcon icon if currency is falsy', () => {
65+
render(getAccountIcon({ ...mock_args, currency: '' }));
66+
67+
expect(screen.getByText(mock_currency_none_icon)).toBeInTheDocument();
68+
});
69+
70+
it('should return an icon specific for a passed currency', () => {
71+
render(getAccountIcon({ ...mock_args, currency: 'USD' }));
72+
73+
expect(screen.getByText(mock_currency_usd_icon)).toBeInTheDocument();
74+
});
75+
76+
it('should return CurrencyNoneIcon icon if currency is not supported', () => {
77+
render(getAccountIcon({ ...mock_args, currency: 'KateCoin' }));
78+
79+
expect(screen.getByText(mock_currency_none_icon)).toBeInTheDocument();
80+
});
81+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import React from 'react';
2+
import { getCurrencyName } from '@deriv/shared';
3+
import { Localize } from '@deriv/translations';
4+
import {
5+
CurrencyBusdIcon,
6+
CurrencyAudIcon,
7+
CurrencyBchIcon,
8+
CurrencyUsdtIcon,
9+
CurrencyBtcIcon,
10+
CurrencyEthIcon,
11+
CurrencyLtcIcon,
12+
CurrencyUsdcIcon,
13+
CurrencyUsdIcon,
14+
CurrencyEurIcon,
15+
CurrencyGbpIcon,
16+
CurrencyNoneIcon,
17+
CurrencyDemoIcon,
18+
CurrencyMultiCollateralDaiIcon,
19+
CurrencyEursIcon,
20+
CurrencyIdkIcon,
21+
CurrencyPaxIcon,
22+
CurrencyTusdIcon,
23+
CurrencyUsdkIcon,
24+
CurrencyXrpIcon,
25+
} from '@deriv/quill-icons';
26+
27+
export const BROKER_CODE = {
28+
MF: 'MF',
29+
CR: 'CR',
30+
VRTC: 'VRTC',
31+
};
32+
33+
export const getAccountTitle = ({
34+
currency,
35+
loginid,
36+
is_virtual,
37+
show_no_currency,
38+
}: {
39+
currency?: string;
40+
loginid?: string;
41+
is_virtual?: boolean;
42+
show_no_currency?: boolean;
43+
}) => {
44+
const account_type = loginid?.replace(/\d/g, '');
45+
46+
if (account_type === BROKER_CODE.MF) {
47+
return <Localize i18n_default_text='Multipliers' />;
48+
}
49+
50+
if (is_virtual) {
51+
return <Localize i18n_default_text='Demo' />;
52+
}
53+
54+
if (!currency) {
55+
return show_no_currency ? <Localize i18n_default_text='No currency assigned' /> : loginid;
56+
}
57+
58+
return getCurrencyName(currency);
59+
};
60+
61+
export const getAccountIcon = ({
62+
currency,
63+
is_virtual,
64+
size,
65+
}: {
66+
currency?: string;
67+
is_virtual?: boolean;
68+
size?: React.ComponentProps<typeof CurrencyDemoIcon>['iconSize'];
69+
}) => {
70+
if (is_virtual) return <CurrencyDemoIcon iconSize={size} />;
71+
if (!currency) return <CurrencyNoneIcon iconSize={size} />;
72+
73+
const key = currency.toUpperCase();
74+
const config = {
75+
AUD: <CurrencyAudIcon iconSize={size} />,
76+
BCH: <CurrencyBchIcon iconSize={size} />,
77+
BUSD: <CurrencyBusdIcon iconSize={size} />,
78+
DAI: <CurrencyMultiCollateralDaiIcon iconSize={size} />,
79+
TUSDT: <CurrencyUsdtIcon iconSize={size} />,
80+
UST: <CurrencyUsdtIcon iconSize={size} />,
81+
EUSDT: <CurrencyUsdtIcon iconSize={size} />,
82+
BTC: <CurrencyBtcIcon iconSize={size} />,
83+
ETH: <CurrencyEthIcon iconSize={size} />,
84+
LTC: <CurrencyLtcIcon iconSize={size} />,
85+
USDC: <CurrencyUsdcIcon iconSize={size} />,
86+
USD: <CurrencyUsdIcon iconSize={size} />,
87+
EUR: <CurrencyEurIcon iconSize={size} />,
88+
GBP: <CurrencyGbpIcon iconSize={size} />,
89+
EURS: <CurrencyEursIcon iconSize={size} />,
90+
IDK: <CurrencyIdkIcon iconSize={size} />,
91+
PAX: <CurrencyPaxIcon iconSize={size} />,
92+
TUSD: <CurrencyTusdIcon iconSize={size} />,
93+
USDK: <CurrencyUsdkIcon iconSize={size} />,
94+
XRP: <CurrencyXrpIcon iconSize={size} />,
95+
};
96+
97+
return config[key as keyof typeof config] ?? <CurrencyNoneIcon iconSize={size} />;
98+
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import Loadable from 'react-loadable';
4+
import AccountActionsDTraderV2 from '../account-actions-dtrader-v2';
5+
6+
const mock_props = {
7+
acc_switcher_disabled_message: 'acc_switcher_disabled_message',
8+
account_switcher_title: 'account_switcher_title',
9+
account_type: 'account_type',
10+
balance: 1000,
11+
currency: 'USD',
12+
is_acc_switcher_on: true,
13+
is_acc_switcher_disabled: false,
14+
is_eu: true,
15+
is_virtual: true,
16+
notifications_count: 0,
17+
toggleAccountsDialog: jest.fn(),
18+
};
19+
const media_query_list = {
20+
matches: true,
21+
addEventListener: jest.fn(),
22+
removeEventListener: jest.fn(),
23+
};
24+
25+
jest.mock('@deriv/quill-icons', () => ({
26+
...jest.requireActual('@deriv/quill-icons'),
27+
LabelPairedBellLgRegularIcon: jest.fn(() => 'LabelPairedBellLgRegularIcon'),
28+
}));
29+
jest.mock('../account-info-dtrader-v2', () => jest.fn(() => 'AccountInfoDTraderV2'));
30+
31+
window.matchMedia = jest.fn().mockImplementation(() => media_query_list);
32+
Loadable.preloadAll();
33+
34+
describe('AccountActionsDTraderV2', () => {
35+
it('should render icon component without Badge count if notifications_count is falsy', () => {
36+
render(<AccountActionsDTraderV2 {...mock_props} />);
37+
38+
expect(screen.getByText('LabelPairedBellLgRegularIcon')).toBeInTheDocument();
39+
});
40+
41+
it('should render icon component with Badge count if notifications_count was passed', () => {
42+
render(<AccountActionsDTraderV2 {...mock_props} notifications_count={2} balance={undefined} />);
43+
44+
expect(screen.getByText('AccountInfoDTraderV2')).toBeInTheDocument();
45+
expect(screen.getByText('LabelPairedBellLgRegularIcon')).toBeInTheDocument();
46+
expect(screen.getByText('2')).toBeInTheDocument();
47+
});
48+
49+
it('should render component even if balance is undefined', () => {
50+
render(<AccountActionsDTraderV2 {...mock_props} balance={undefined} />);
51+
52+
expect(screen.getByText('AccountInfoDTraderV2')).toBeInTheDocument();
53+
expect(screen.getByText('LabelPairedBellLgRegularIcon')).toBeInTheDocument();
54+
});
55+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import AccountGroupWrapper from '../account-group-wrapper-dtrader-v2';
4+
5+
const children = 'Children';
6+
const separator_text = 'separator_text';
7+
const mock_props = {
8+
separator_text,
9+
show_bottom_separator: false,
10+
};
11+
12+
describe('AccountGroupWrapper', () => {
13+
it('should render only passed children if separator_text was not passed', () => {
14+
render(
15+
<AccountGroupWrapper>
16+
<div>{children}</div>
17+
</AccountGroupWrapper>
18+
);
19+
20+
expect(screen.getByText(children)).toBeInTheDocument();
21+
expect(screen.queryByText(separator_text)).not.toBeInTheDocument();
22+
});
23+
24+
it('should render passed children and separator_text if it was passed', () => {
25+
render(
26+
<AccountGroupWrapper {...mock_props}>
27+
<div>{children}</div>
28+
</AccountGroupWrapper>
29+
);
30+
31+
expect(screen.getByText(children)).toBeInTheDocument();
32+
expect(screen.getByText(separator_text)).toBeInTheDocument();
33+
});
34+
});
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
4+
import AccountInfoDTraderV2 from '../account-info-dtrader-v2';
5+
6+
const account_switcher_title = 'account_switcher_title';
7+
8+
jest.mock('../../account-info-wrapper', () => jest.fn(({ children }) => children));
9+
jest.mock('../account-switcher-dtrader-v2', () => jest.fn(() => 'AccountSwitcherDTraderV2'));
10+
11+
const media_query_list = {
12+
matches: true,
13+
addEventListener: jest.fn(),
14+
removeEventListener: jest.fn(),
15+
};
16+
17+
window.matchMedia = jest.fn().mockImplementation(() => media_query_list);
18+
19+
describe('AccountInfoDTraderV2', () => {
20+
let mock_props: React.ComponentProps<typeof AccountInfoDTraderV2>;
21+
22+
beforeEach(() => {
23+
mock_props = {
24+
acc_switcher_disabled_message: 'acc_switcher_disabled_message',
25+
account_switcher_title,
26+
balance: 100,
27+
currency: 'USD',
28+
is_dialog_on: true,
29+
is_virtual: true,
30+
is_disabled: false,
31+
toggleDialog: jest.fn(),
32+
};
33+
});
34+
35+
afterEach(() => jest.clearAllMocks());
36+
37+
it('should render component with default passed props', () => {
38+
render(<AccountInfoDTraderV2 {...mock_props} />);
39+
40+
expect(screen.getByText(account_switcher_title)).toBeInTheDocument();
41+
expect(screen.getByText('100 USD')).toBeInTheDocument();
42+
expect(screen.getByText('AccountSwitcherDTraderV2')).toBeInTheDocument();
43+
});
44+
45+
it('should not call toggleDialog if user clicks on account switcher and is_disabled === true', () => {
46+
render(<AccountInfoDTraderV2 {...mock_props} is_disabled />);
47+
48+
expect(mock_props.toggleDialog).not.toBeCalled();
49+
userEvent.click(screen.getByText(account_switcher_title));
50+
expect(mock_props.toggleDialog).not.toBeCalled();
51+
});
52+
53+
it('should call toggleDialog if user clicks on account switcher and is_disabled === false', () => {
54+
render(<AccountInfoDTraderV2 {...mock_props} />);
55+
56+
expect(mock_props.toggleDialog).not.toBeCalled();
57+
userEvent.click(screen.getByText(account_switcher_title));
58+
expect(mock_props.toggleDialog).toBeCalled();
59+
});
60+
61+
it('should render "No currency assigned" if currency is falsy', () => {
62+
render(<AccountInfoDTraderV2 {...mock_props} currency='' />);
63+
64+
expect(screen.getByText('No currency assigned')).toBeInTheDocument();
65+
});
66+
67+
it('should render "No currency assigned" if currency is falsy and balance was not passed', () => {
68+
render(<AccountInfoDTraderV2 {...mock_props} currency='' balance={undefined} />);
69+
70+
expect(screen.getByText('No currency assigned')).toBeInTheDocument();
71+
});
72+
73+
it('should not render account_switcher_title if it was not passed', () => {
74+
render(<AccountInfoDTraderV2 {...mock_props} account_switcher_title={undefined} />);
75+
76+
expect(screen.queryByText(account_switcher_title)).not.toBeInTheDocument();
77+
});
78+
79+
it('should call toggleDialog with "false" if user clicks outside the modal when it was open', () => {
80+
render(<AccountInfoDTraderV2 {...mock_props} />);
81+
82+
expect(mock_props.toggleDialog).not.toBeCalled();
83+
userEvent.click(screen.getByText(account_switcher_title));
84+
expect(mock_props.toggleDialog).toBeCalled();
85+
userEvent.click(screen.getByTestId('dt-actionsheet-overlay'));
86+
expect(mock_props.toggleDialog).toBeCalledWith(false);
87+
});
88+
});

0 commit comments

Comments
 (0)