diff --git a/packages/appstore/src/components/main-title-bar/asset-summary.tsx b/packages/appstore/src/components/main-title-bar/asset-summary.tsx index 32cce8d3c4dd..ca0954b074eb 100644 --- a/packages/appstore/src/components/main-title-bar/asset-summary.tsx +++ b/packages/appstore/src/components/main-title-bar/asset-summary.tsx @@ -6,14 +6,14 @@ import BalanceText from 'Components/elements/text/balance-text'; import { observer, useStore } from '@deriv/stores'; import './asset-summary.scss'; import TotalAssetsLoader from 'Components/pre-loader/total-assets-loader'; -import { useTotalAccountBalance, useCfdAccounts, usePlatformAccounts } from '@deriv/hooks'; +import { useTotalAccountBalance, useCFDAccounts, usePlatformAccounts } from '@deriv/hooks'; const AssetSummary = observer(() => { const { traders_hub, client } = useStore(); const { selected_account_type, is_eu_user, no_CR_account, no_MF_account } = traders_hub; const { is_logging_in, is_switching, default_currency } = client; const { real: platform_real_accounts, demo: platform_demo_account } = usePlatformAccounts(); - const { real: cfd_real_accounts, demo: cfd_demo_accounts } = useCfdAccounts(); + const { real: cfd_real_accounts, demo: cfd_demo_accounts } = useCFDAccounts(); const platform_real_balance = useTotalAccountBalance(platform_real_accounts); const cfd_real_balance = useTotalAccountBalance(cfd_real_accounts); const cfd_demo_balance = useTotalAccountBalance(cfd_demo_accounts); @@ -54,7 +54,7 @@ const AssetSummary = observer(() => { { + test('should return empty array when client has no CFD accounts', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAccounts(), { wrapper }); + + expect(result.current.all.length).toBe(0); + expect(result.current.demo.length).toBe(0); + expect(result.current.real.length).toBe(0); + }); + + test('should return proper data when client only has CFD demo accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'demo', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAccounts(), { wrapper }); + + expect(result.current.all.length).toBe(1); + expect(result.current.demo.length).toBe(1); + expect(result.current.real.length).toBe(0); + }); + + test('should return proper data when client only has CFD real accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAccounts(), { wrapper }); + + expect(result.current.all.length).toBe(1); + expect(result.current.demo.length).toBe(0); + expect(result.current.real.length).toBe(1); + }); + + test('should return proper data when client only has both CFD real and demo accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'demo', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAccounts(), { wrapper }); + + expect(result.current.all.length).toBe(2); + expect(result.current.demo.length).toBe(1); + expect(result.current.real.length).toBe(1); + }); +}); diff --git a/packages/hooks/src/__tests__/useCFDAllAccounts.spec.tsx b/packages/hooks/src/__tests__/useCFDAllAccounts.spec.tsx new file mode 100644 index 000000000000..74a602c08adb --- /dev/null +++ b/packages/hooks/src/__tests__/useCFDAllAccounts.spec.tsx @@ -0,0 +1,87 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useCFDAllAccounts from '../useCFDAllAccounts'; + +describe('useCFDAllAccounts', () => { + test('should return empty array when client has no CFD accounts', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAllAccounts(), { wrapper }); + + expect(result.current.length).toBe(0); + }); + + test('should return proper data when client has MT5 accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAllAccounts(), { wrapper }); + + expect(result.current.length).toBe(1); + }); + + test('should return proper data when client has dxtrade accounts', async () => { + const mock = mockStore({ + client: { + dxtrade_accounts_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAllAccounts(), { wrapper }); + + expect(result.current.length).toBe(1); + }); + + test('should return proper data when client has both MT5 and dxtrade accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'real', + balance: 1000, + currency: 'USD', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDAllAccounts(), { wrapper }); + + expect(result.current.length).toBe(2); + }); +}); diff --git a/packages/hooks/src/__tests__/useCFDDemoAccounts.spec.tsx b/packages/hooks/src/__tests__/useCFDDemoAccounts.spec.tsx new file mode 100644 index 000000000000..d2015000c2bb --- /dev/null +++ b/packages/hooks/src/__tests__/useCFDDemoAccounts.spec.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useCFDDemoAccounts from '../useCFDDemoAccounts'; + +describe('useCFDDemoAccounts', () => { + test('should return empty array when user has no CFD accounts', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDDemoAccounts(), { wrapper }); + + expect(result.current?.length).toBe(0); + }); + + test('should return empty array when user has no CFD demo accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'real', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDDemoAccounts(), { wrapper }); + + expect(result.current?.length).toBe(0); + }); + + test('should return proper data when user has CFD demo accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'demo', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'real', + }, + { + account_type: 'demo', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDDemoAccounts(), { wrapper }); + + expect(result.current?.length).toBe(2); + }); +}); diff --git a/packages/hooks/src/__tests__/useCFDRealAccounts.spec.tsx b/packages/hooks/src/__tests__/useCFDRealAccounts.spec.tsx new file mode 100644 index 000000000000..c796f02d09fe --- /dev/null +++ b/packages/hooks/src/__tests__/useCFDRealAccounts.spec.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useCFDRealAccounts from '../useCFDRealAccounts'; + +describe('useCFDRealAccounts', () => { + test('should return empty array when user has no CFD accounts', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDRealAccounts(), { wrapper }); + + expect(result.current?.length).toBe(0); + }); + + test('should return empty array when user has no CFD real accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'demo', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'demo', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDRealAccounts(), { wrapper }); + + expect(result.current?.length).toBe(0); + }); + + test('should return proper data when user has CFD real accounts', async () => { + const mock = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + }, + ], + dxtrade_accounts_list: [ + { + account_type: 'real', + }, + { + account_type: 'demo', + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useCFDRealAccounts(), { wrapper }); + + expect(result.current?.length).toBe(2); + }); +}); diff --git a/packages/hooks/src/__tests__/useExchangeRate.spec.tsx b/packages/hooks/src/__tests__/useExchangeRate.spec.tsx new file mode 100644 index 000000000000..19a574ea65eb --- /dev/null +++ b/packages/hooks/src/__tests__/useExchangeRate.spec.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useExchangeRate from '../useExchangeRate'; + +describe('useExchangeRate', () => { + test('should return 1 if currency is not found', async () => { + const mock = mockStore({ + exchange_rates: { + data: { + base_currency: 'USD', + rates: { + EUR: 1.3, + GBP: 1.4, + ETH: 0.0001, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useExchangeRate(), { wrapper }); + const rate = result.current.getRate('JPY'); + expect(rate).toBe(1); + }); + + test('should return correct rate for the given currency other than USD', async () => { + const mock = mockStore({ + exchange_rates: { + data: { + rates: { + EUR: 1.3, + GBP: 1.5, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useExchangeRate(), { wrapper }); + const rate = result.current.getRate('EUR'); + expect(rate).toBe(1.3); + }); +}); diff --git a/packages/hooks/src/__tests__/usePlatformAccounts.spec.tsx b/packages/hooks/src/__tests__/usePlatformAccounts.spec.tsx new file mode 100644 index 000000000000..d46a4cc10bac --- /dev/null +++ b/packages/hooks/src/__tests__/usePlatformAccounts.spec.tsx @@ -0,0 +1,92 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import usePlatformAccounts from '../usePlatformAccounts'; + +describe('usePlatformRealAccounts', () => { + test('should return proper data when user has no platform demo and real accounts', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformAccounts(), { wrapper }); + + expect(result.current.demo).toBe(undefined); + expect(result.current.real.length).toBe(0); + }); + + test('should return proper data when user only has platform demo account', async () => { + const mock = mockStore({ + client: { + accounts: { + VR1234: { + is_virtual: 1, + loginid: 'VR1234', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformAccounts(), { wrapper }); + + expect(result.current.demo?.loginid).toBe(mock.client.accounts.VR1234.loginid); + expect(result.current.real.length).toBe(0); + }); + + test('should return proper data when user only has platform real account', async () => { + const mock = mockStore({ + client: { + accounts: { + CR1234: { + is_virtual: 0, + loginid: 'CR1234', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformAccounts(), { wrapper }); + + expect(result.current.demo?.loginid).toBe(undefined); + expect(result.current.real.length).toBe(1); + }); + + test('should return proper data when user has both real and demo accounts', async () => { + const mock = mockStore({ + client: { + accounts: { + CR1234: { + is_virtual: 0, + loginid: 'VR1234', + landing_company_shortcode: 'svg', + }, + MF1234: { + is_virtual: 0, + loginid: 'VR1235', + landing_company_shortcode: 'maltainvest', + }, + VR1235: { + is_virtual: 1, + loginid: 'VR1236', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformAccounts(), { wrapper }); + + expect(result.current.demo?.loginid).toBe(mock.client.accounts.VR1235.loginid); + expect(result.current.real.length).toBe(1); + expect(result.current.real[0].landing_company_shortcode).toBe('svg'); + }); +}); diff --git a/packages/hooks/src/__tests__/usePlatformDemoAccount.spec.tsx b/packages/hooks/src/__tests__/usePlatformDemoAccount.spec.tsx new file mode 100644 index 000000000000..680f32547cd7 --- /dev/null +++ b/packages/hooks/src/__tests__/usePlatformDemoAccount.spec.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import usePlatformDemoAccount from '../usePlatformDemoAccount'; + +describe('usePlatformDemoAccount', () => { + test('should return undefined when user has no platform demo accounts', async () => { + const mock = mockStore({ + client: { + accounts: { + VR1234: { + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformDemoAccount(), { wrapper }); + + expect(result.current).toBe(undefined); + }); + + test('should return proper data when user has platform demo account', async () => { + const mock = mockStore({ + client: { + accounts: { + VR1234: { + is_virtual: 1, + loginid: 'VR1234', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformDemoAccount(), { wrapper }); + + expect(result.current?.loginid).toBe(mock.client.accounts.VR1234.loginid); + }); +}); diff --git a/packages/hooks/src/__tests__/usePlatformRealAccounts.spec.tsx b/packages/hooks/src/__tests__/usePlatformRealAccounts.spec.tsx new file mode 100644 index 000000000000..2388882fae81 --- /dev/null +++ b/packages/hooks/src/__tests__/usePlatformRealAccounts.spec.tsx @@ -0,0 +1,93 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import usePlatformRealAccounts from '../usePlatformRealAccounts'; + +describe('usePlatformRealAccounts', () => { + test('should return null when user has no platform real accounts', async () => { + const mock = mockStore({ + client: { + accounts: { + VR1234: { + is_virtual: 1, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformRealAccounts(), { wrapper }); + + expect(result.current.length).toBe(0); + }); + + test('should return svg accounts when user has real account and switch to non-eu accounts', async () => { + const mock = mockStore({ + traders_hub: { + is_eu_user: false, + }, + client: { + accounts: { + CR1234: { + is_virtual: 0, + loginid: 'VR1234', + landing_company_shortcode: 'svg', + }, + MF1234: { + is_virtual: 0, + loginid: 'VR1234', + landing_company_shortcode: 'maltainvest', + }, + VR1235: { + is_virtual: 1, + loginid: 'VR1234', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformRealAccounts(), { wrapper }); + + expect(result.current.length).toBe(1); + expect(result.current[0].landing_company_shortcode).toBe('svg'); + }); + + test('should return maltainvest accounts when user has real account and switch to eu accounts', async () => { + const mock = mockStore({ + traders_hub: { + is_eu_user: true, + }, + client: { + accounts: { + CR1234: { + is_virtual: 0, + loginid: 'VR1234', + landing_company_shortcode: 'svg', + }, + MF1234: { + is_virtual: 0, + loginid: 'VR1234', + landing_company_shortcode: 'maltainvest', + }, + VR1235: { + is_virtual: 1, + loginid: 'VR1234', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => usePlatformRealAccounts(), { wrapper }); + + expect(result.current.length).toBe(1); + expect(result.current[0].landing_company_shortcode).toBe('maltainvest'); + }); +}); diff --git a/packages/hooks/src/__tests__/useTotalAccountBalance.spec.tsx b/packages/hooks/src/__tests__/useTotalAccountBalance.spec.tsx new file mode 100644 index 000000000000..943a2d1e1a47 --- /dev/null +++ b/packages/hooks/src/__tests__/useTotalAccountBalance.spec.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useTotalAccountBalance from '../useTotalAccountBalance'; + +describe('useTotalAccountBalance', () => { + test('should return zero when user has no account', async () => { + const mock = mockStore({}); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useTotalAccountBalance(mock.client.active_accounts), { wrapper }); + + expect(result.current.balance).toBe(0); + }); + + test('should return total balance correctly when user has multiple accounts', async () => { + const mock = mockStore({ + exchange_rates: { + data: { + rates: { + EUR: 2, + AUD: 3, + }, + }, + }, + client: { + active_accounts: [ + { + currency: 'AUD', + balance: 300, + }, + { + currency: 'EUR', + balance: 200, + }, + ], + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useTotalAccountBalance(mock.client.active_accounts), { wrapper }); + + expect(result.current.balance).toBe(200); + }); +}); diff --git a/packages/hooks/src/__tests__/useTotalAssetCurrency.spec.tsx b/packages/hooks/src/__tests__/useTotalAssetCurrency.spec.tsx new file mode 100644 index 000000000000..1d2ddaf4c034 --- /dev/null +++ b/packages/hooks/src/__tests__/useTotalAssetCurrency.spec.tsx @@ -0,0 +1,237 @@ +import * as React from 'react'; +import { mockStore, StoreProvider } from '@deriv/stores'; +import { renderHook } from '@testing-library/react-hooks'; +import useRealTotalAssetCurrency from '../useTotalAssetCurrency'; + +describe('useRealTotalAssetCurrency', () => { + test('should return default currency when user has no account', async () => { + const mock = mockStore({ + client: { + default_currency: 'EUR', + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + expect(result.current).toBe(mock.client.default_currency); + }); + + test('should return default currency when user has no real account', async () => { + const mock = mockStore({ + client: { + default_currency: 'EUR', + accounts: { + acc1: { + currency: 'JPY', + is_virtual: 1, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + expect(result.current).toBe(mock.client.default_currency); + }); + + test('should return proper currency when user has non_crypto account', async () => { + const mock = mockStore({ + client: { + is_crypto: (currency: string) => currency === 'BTC', + accounts: { + crypto_acc: { + currency: 'BTC', + is_virtual: 0, + }, + non_crypto_acc: { + currency: 'AUD', + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(mock.client.accounts.non_crypto_acc.currency); + }); + + test('should return empty string when user has non_crypto account with no currency set', async () => { + const mock = mockStore({ + client: { + is_crypto: (currency: string) => currency === 'BTC', + accounts: { + crypto_acc: { + currency: 'BTC', + is_virtual: 0, + }, + non_crypto_acc: { + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(''); + }); + + test("should return the first account's currency when user only has crypto account", async () => { + const mock = mockStore({ + client: { + is_crypto: (currency: string) => ['BTC', 'ETH'].includes(currency) || true, + accounts: { + eth_acc: { + currency: 'ETH', + is_virtual: 0, + }, + btc_acc: { + currency: 'BTC', + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + const first_account_currency = mock.client.accounts[Object.keys(mock.client.accounts)[0]].currency; + expect(result.current).toBe(first_account_currency); + }); + + test('should return the current selected currency when user only has crypto account and is_crypto() is false', async () => { + const mock = mockStore({ + client: { + is_crypto: (currency: string) => ['BTC', 'ETH'].includes(currency) || false, + currency: 'USDC', + accounts: { + eth_acc: { + currency: 'ETH', + is_virtual: 0, + }, + usdc_acc: { + currency: 'USDC', + is_virtual: 0, + }, + btc_acc: { + currency: 'BTC', + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(mock.client.currency); + }); + + test('should return undefined when user only has crypto account with no currency set', async () => { + const mock = mockStore({ + client: { + is_crypto: (currency: string) => ['BTC', 'ETH'].includes(currency) || true, + accounts: { + crypto_acc: { + is_virtual: 0, + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(undefined); + }); + + test("should return MF account's currency when user switch to eu account type", async () => { + const mock = mockStore({ + traders_hub: { + is_eu_user: true, + }, + client: { + current_fiat_currency: 'EUR', + is_crypto: (currency: string) => ['BTC', 'ETH'].includes(currency) || true, + accounts: { + btc_acc: { + currency: 'BTC', + is_virtual: 0, + landing_company_shortcode: 'svg', + }, + eth_acc: { + currency: 'ETH', + is_virtual: 0, + landing_company_shortcode: 'svg', + }, + MF1234: { + currency: 'EUR', + is_virtual: 0, + landing_company_shortcode: 'maltainvest', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(mock.client.accounts.MF1234.currency); + }); + + test("should return default currency when user switch to eu account type but MF account's currency is not set", async () => { + const mock = mockStore({ + traders_hub: { + is_eu_user: true, + }, + client: { + default_currency: 'GBP', + is_crypto: (currency: string) => ['BTC', 'ETH'].includes(currency) || true, + accounts: { + btc_acc: { + currency: 'BTC', + is_virtual: 0, + landing_company_shortcode: 'svg', + }, + eth_acc: { + currency: 'ETH', + is_virtual: 0, + landing_company_shortcode: 'svg', + }, + MF1234: { + currency: 'EUR', + is_virtual: 0, + landing_company_shortcode: 'maltainvest', + }, + }, + }, + }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + const { result } = renderHook(() => useRealTotalAssetCurrency(), { wrapper }); + + expect(result.current).toBe(mock.client.default_currency); + }); +}); diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 245cd16c5a0b..f4555a7a9cfe 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -1,9 +1,9 @@ export { default as useAccountTransferVisible } from './useAccountTransferVisible'; +export { default as useCFDAccounts } from './useCFDAccounts'; export { default as useCFDAllAccounts } from './useCFDAllAccounts'; export { default as useCFDDemoAccounts } from './useCFDDemoAccounts'; export { default as useCFDRealAccounts } from './useCFDRealAccounts'; export { default as useCashierLocked } from './useCashierLocked'; -export { default as useCfdAccounts } from './useCfdAccounts'; export { default as useCountdown } from './useCountdown'; export { default as useDepositLocked } from './useDepositLocked'; export { default as useExchangeRate } from './useExchangeRate'; diff --git a/packages/hooks/src/useCfdAccounts.ts b/packages/hooks/src/useCFDAccounts.ts similarity index 74% rename from packages/hooks/src/useCfdAccounts.ts rename to packages/hooks/src/useCFDAccounts.ts index 8641de8ff8dd..5da45e4d102d 100644 --- a/packages/hooks/src/useCfdAccounts.ts +++ b/packages/hooks/src/useCFDAccounts.ts @@ -1,4 +1,4 @@ -import useCFDAccounts from './useCFDAllAccounts'; +import useCFDAllAccounts from './useCFDAllAccounts'; import useCFDDemoAccounts from './useCFDDemoAccounts'; import useCFDRealAccounts from './useCFDRealAccounts'; @@ -7,8 +7,8 @@ import useCFDRealAccounts from './useCFDRealAccounts'; * and it returns different cfd account types which are demo, real, and all */ -const useGetCfdAccounts = () => { - const all_cfd_accounts = useCFDAccounts(); +const useCFDAccounts = () => { + const all_cfd_accounts = useCFDAllAccounts(); const cfd_demo_accounts = useCFDDemoAccounts(); const cfd_real_accounts = useCFDRealAccounts(); @@ -19,4 +19,4 @@ const useGetCfdAccounts = () => { }; }; -export default useGetCfdAccounts; +export default useCFDAccounts; diff --git a/packages/hooks/src/useTotalAccountBalance.ts b/packages/hooks/src/useTotalAccountBalance.ts index 741f4e83c600..5ab91f88ecaf 100644 --- a/packages/hooks/src/useTotalAccountBalance.ts +++ b/packages/hooks/src/useTotalAccountBalance.ts @@ -15,8 +15,8 @@ const useTotalAccountBalance = (accounts: { balance?: number; currency?: string if (!accounts.length) return { balance: 0, currency: total_assets_real_currency }; const balance = accounts.reduce((total, account) => { - const base_rate = getRate(total_assets_real_currency); - const rate = getRate(account.currency || total_assets_real_currency); + const base_rate = getRate(total_assets_real_currency || ''); + const rate = getRate(account.currency || total_assets_real_currency || ''); const exchange_rate = base_rate / rate; return total + (account.balance || 0) * exchange_rate; diff --git a/packages/stores/src/mockStore.ts b/packages/stores/src/mockStore.ts index 1e66b0ccb439..8f3a18b73895 100644 --- a/packages/stores/src/mockStore.ts +++ b/packages/stores/src/mockStore.ts @@ -1,20 +1,11 @@ import merge from 'lodash.merge'; import { TStores } from '../types'; -const mock = (): TStores => { +const mock = (): TStores & { is_mock: boolean } => { return { + is_mock: true, client: { - accounts: { - loginid: { - account_type: 'trading', - created_at: 1674633682, - currency: 'USD', - is_disabled: 0, - is_virtual: 0, - excluded_until: 0, - landing_company_name: 'svg', - }, - }, + accounts: {}, active_account_landing_company: '', account_limits: { daily_transfers: { diff --git a/packages/stores/src/storeProvider.tsx b/packages/stores/src/storeProvider.tsx index 3c0b18a1b872..e7708e3bb6b2 100644 --- a/packages/stores/src/storeProvider.tsx +++ b/packages/stores/src/storeProvider.tsx @@ -5,18 +5,21 @@ import { ExchangeRatesProvider } from './providers'; import type { TCoreStores, TStores } from '../types'; const StoreProvider = ({ children, store }: PropsWithChildren<{ store: TCoreStores }>) => { - const memoizedValue: TStores = useMemo( - () => ({ + const memoizedValue: TStores = useMemo(() => { + // If the store is mocked for testing purposes, then return the mocked value. + if ('is_mock' in store && store.is_mock) return store as unknown as TStores; + + // Otherwise, instantiate store and return it. + return { ...store, exchange_rates: new ExchangeRatesStore(), - }), - [store] - ); + }; + }, [store]); useEffect(() => { return () => { Object.values(memoizedValue).forEach(value => { - if ('unmount' in value) value.unmount(); + if (typeof value === 'object' && 'unmount' in value) value.unmount(); }); }; }, [memoizedValue]); diff --git a/packages/stores/types.ts b/packages/stores/types.ts index e114d70cce3c..76fbce289412 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -90,7 +90,7 @@ type TNotification = type TAccountStatus = Omit & Partial>; type TClientStore = { - accounts: { [k: string]: TAccount }; + accounts: { [k: string]: TActiveAccount }; active_accounts: TActiveAccount[]; active_account_landing_company: string; account_limits: {