Skip to content

Commit

Permalink
Maryia/Merged from master & resolved conflicts + small style fix for …
Browse files Browse the repository at this point in the history
…dmt5 dashboard (#27)

* Niloofar / Indicators documentation review (deriv-com#5825)

* indicators documentation review

* resolved review comment

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* Niloofar / Trader documentation review (deriv-com#5792)

* edit some parts of trader docs

* remove extra information from traders docs

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* shayan / cfd documentation updated (deriv-com#5800)

* docs/ cfd readme.md updated

* Update README.md

* docs/ Readme file updated

* docs/ readme file updated

* docs/ Update packages/cfd/README.md

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* docs/ Update packages/cfd/README.md

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* docs /Update packages/cfd/README.md

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* docs/ update readme file

* doc/ updated readme file

* doc/ updated readme file

* doc/ updated readme file

Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>

* yauheni / Notify users about sharing tokens with admin scope selected (deriv-com#5741)

* yauheni / Notify users about sharing tokens with admin scope selected, added note

* tests fix

* created token scope styling

* deleted option test fix

* token value fild markup

* clipboard with warning dialog implemented

* responsive version done, tests refactoring

* dialog fix for admin scope

* check commit after rebuild

* css fixes, refactor after review

* svg icon fill color fix

* inline note fix

* Delete package-lock.json

* fix commit

* fix

* dots component placing fix

* dialog fixes

* api token tests fix

* css fix for token table

* review fixes

* naming fix, close delete dialog timeout deleted

* testcase fix

* localize fix

* admin note message change

* copy token hover message fix

* token alignment eye button fix

* ok button capital letters fix

* delete button hover fix, clipboard refactor

Co-authored-by: “yauheni-kryzhyk-deriv” <“yauheni@deriv.me”>

* farrah/ fixed cfd lint errors (deriv-com#5607)

* ci/ exclude dist files from eslint scan

* ci/ disable spaced-comment

* ci/ exclude lib dir from eslint scan

* fixed cfd eslint errors

* renamed variables and fixed types

* fixed missing return function

* refactor code

* fixed cleanup function

* fixed invalid property document_file on submit

Co-authored-by: Ali(Ako) Hosseini <ali.hosseini@firstsource.tech>

* yashim/feat: add TTI Measurement  (deriv-com#5764)

* feat: add TTI Measurement

* fix: security error

* fix: add regex to fire only in specific domain

* chore: remove console log

* fix: remove TTI script. Offload to GTM

* chore: revert gtm loading changes

* translations: 📚 sync translations with crowdin (deriv-com#5965)

Co-authored-by: DerivFE <80095553+DerivFE@users.noreply.github.com>

* chore: removed unused prop from jurisdiction card

* fix for dmt5 server maintenance & download center styles

Co-authored-by: Niloofar Sadeghi <93518187+niloo-fs@users.noreply.github.com>
Co-authored-by: Yashim Wong <75345074+yashim-deriv@users.noreply.github.com>
Co-authored-by: Shayan Khaleghparast <100833613+iman-fs@users.noreply.github.com>
Co-authored-by: yauheni-kryzhyk-deriv <103182683+yauheni-kryzhyk-deriv@users.noreply.github.com>
Co-authored-by: “yauheni-kryzhyk-deriv” <“yauheni@deriv.me”>
Co-authored-by: Farrah Mae Ochoa <82315152+farrah-deriv@users.noreply.github.com>
Co-authored-by: Ali(Ako) Hosseini <ali.hosseini@firstsource.tech>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: DerivFE <80095553+DerivFE@users.noreply.github.com>
  • Loading branch information
10 people authored Jul 13, 2022
1 parent 4d12352 commit 92bff52
Show file tree
Hide file tree
Showing 62 changed files with 1,133 additions and 733 deletions.
165 changes: 120 additions & 45 deletions packages/account/src/Components/api-token/__tests__/api-token.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ApiToken from '../api-token';

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
getPropertyValue: jest.fn().mockReturnValue([]),
getPropertyValue: jest.fn(() => []),
isDesktop: jest.fn(() => true),
isMobile: jest.fn(() => false),
useIsMounted: jest.fn().mockImplementation(() => () => true),
Expand All @@ -16,19 +16,35 @@ jest.mock('@deriv/components', () => ({
Loading: () => <div>Loading</div>,
}));

let modal_root_el;
beforeAll(() => {
modal_root_el = document.createElement('div');
modal_root_el.setAttribute('id', 'modal_root');
document.body.appendChild(modal_root_el);
});

afterAll(() => {
document.body.removeChild(modal_root_el);
});

describe('<ApiToken/>', () => {
const admin_description = 'Open accounts, manage settings, manage token usage, and more.';
const admin_scope_description =
'This scope will allow third-party apps to open accounts for you, manage your settings and token usage, and more.';
const admin_scope_note =
'To avoid loss of funds, do not share tokens with the Admin scope with unauthorised parties.';
const learn_more_title = 'Learn more about API token';
const read_scope_description =
'This scope will allow third-party apps to view your account activity, settings, limits, balance sheets, trade purchase history, and more.';
const our_access_description =
"To access our mobile apps and other third-party apps, you'll first need to generate an API token.";
const payments_description = 'Withdraw to payment agents, and transfer funds between accounts.';
const trading_info_scope_description =
'This scope will allow third-party apps to withdraw to payment agents and make inter-account transfers for you.';
const select_scopes_msg = 'Select scopes based on the access you need.';
const token_creation_description = "Name your token and click on 'Create' to generate your token.";
const token_using_description = 'Copy and paste the token into the app.';
const trade_description = 'Buy and sell contracts, renew expired purchases, and top up demo accounts.';
const trading_info_description = 'View the trading history.';
const view_activity_msg =
'View account activity such as settings, limits, balance sheets, trade purchase history, and more.';
const trade_scope_description =
'This scope will allow third-party apps to buy and sell contracts for you, renew your expired purchases, and top up your demo accounts.';
const trading_info_description = 'This scope will allow third-party apps to view your trading history.';
const your_access_description =
"To access your mobile apps and other third-party apps, you'll first need to generate an API token.";

Expand Down Expand Up @@ -63,15 +79,16 @@ describe('<ApiToken/>', () => {

expect(mock_props.ws.authorized.apiToken).toHaveBeenCalled();

expect(await screen.findByText(admin_description)).toBeInTheDocument();
expect(await screen.findByText(payments_description)).toBeInTheDocument();
expect(await screen.findByText(admin_scope_description)).toBeInTheDocument();
expect(await screen.findByText(admin_scope_note)).toBeInTheDocument();
expect(await screen.findByText(trading_info_scope_description)).toBeInTheDocument();
expect(await screen.findByText(select_scopes_msg)).toBeInTheDocument();
expect(await screen.findByText(token_creation_description)).toBeInTheDocument();
expect(await screen.findByText(token_using_description)).toBeInTheDocument();
expect(await screen.findByText(trade_description)).toBeInTheDocument();
expect(await screen.findByText(trade_scope_description)).toBeInTheDocument();
expect(await screen.findByText(trading_info_description)).toBeInTheDocument();
expect(await screen.findByText(your_access_description)).toBeInTheDocument();
expect(await screen.findByText(view_activity_msg)).toBeInTheDocument();
expect(await screen.findByText(read_scope_description)).toBeInTheDocument();
expect(screen.queryByText(learn_more_title)).not.toBeInTheDocument();
});

Expand All @@ -83,16 +100,17 @@ describe('<ApiToken/>', () => {
expect(mock_props.ws.authorized.apiToken).toHaveBeenCalled();
expect(screen.getByText('Loading')).toBeInTheDocument();

expect(screen.queryByText(admin_description)).not.toBeInTheDocument();
expect(screen.queryByText(admin_scope_description)).not.toBeInTheDocument();
expect(screen.queryByText(admin_scope_note)).not.toBeInTheDocument();
expect(screen.queryByText(learn_more_title)).not.toBeInTheDocument();
expect(screen.queryByText(payments_description)).not.toBeInTheDocument();
expect(screen.queryByText(trading_info_scope_description)).not.toBeInTheDocument();
expect(screen.queryByText(select_scopes_msg)).not.toBeInTheDocument();
expect(screen.queryByText(token_creation_description)).not.toBeInTheDocument();
expect(screen.queryByText(token_using_description)).not.toBeInTheDocument();
expect(screen.queryByText(trade_description)).not.toBeInTheDocument();
expect(screen.queryByText(trade_scope_description)).not.toBeInTheDocument();
expect(screen.queryByText(trading_info_description)).not.toBeInTheDocument();
expect(screen.queryByText(your_access_description)).not.toBeInTheDocument();
expect(screen.queryByText(view_activity_msg)).not.toBeInTheDocument();
expect(screen.queryByText(read_scope_description)).not.toBeInTheDocument();
});

it('should render ApiToken component without app_settings and footer for mobile', async () => {
Expand All @@ -101,14 +119,15 @@ describe('<ApiToken/>', () => {

render(<ApiToken {...mock_props} />);

expect(await screen.findByText(admin_description)).toBeInTheDocument();
expect(await screen.findByText(payments_description)).toBeInTheDocument();
expect(await screen.findByText(admin_scope_description)).toBeInTheDocument();
expect(await screen.findByText(admin_scope_note)).toBeInTheDocument();
expect(await screen.findByText(trading_info_scope_description)).toBeInTheDocument();
expect(await screen.findByText(select_scopes_msg)).toBeInTheDocument();
expect(await screen.findByText(token_creation_description)).toBeInTheDocument();
expect(await screen.findByText(token_using_description)).toBeInTheDocument();
expect(await screen.findByText(trade_description)).toBeInTheDocument();
expect(await screen.findByText(trade_scope_description)).toBeInTheDocument();
expect(await screen.findByText(trading_info_description)).toBeInTheDocument();
expect(await screen.findByText(view_activity_msg)).toBeInTheDocument();
expect(await screen.findByText(read_scope_description)).toBeInTheDocument();
expect(screen.queryByText(learn_more_title)).not.toBeInTheDocument();
});

Expand Down Expand Up @@ -201,57 +220,116 @@ describe('<ApiToken/>', () => {
{
display_name: 'Second test token',
last_used: '',
scopes: ['Read', 'Payments', 'rade'],
scopes: ['Read', 'Payments', 'Trade'],
token: 'GHjaD2f4gDg5gSE',
valid_for_ip: '',
},
]);

render(<ApiToken {...mock_props} />);

expect(await screen.findByText('Action')).toBeInTheDocument();
expect(await screen.findByText('First test token')).toBeInTheDocument();
expect(await screen.findByText('Last used')).toBeInTheDocument();
expect(await screen.findByText('Name')).toBeInTheDocument();
expect(await screen.findByText('Token')).toBeInTheDocument();
expect(await screen.findByText('Scopes')).toBeInTheDocument();
expect(await screen.findByText('Second test token')).toBeInTheDocument();

const delete_btns_1 = await screen.findAllByRole('button', { name: /delete/i });
const delete_btns_1 = screen.getAllByTestId('dt_token_delete_icon');
expect(delete_btns_1.length).toBe(2);

fireEvent.click(delete_btns_1[0]);
const delete_btns_2 = await screen.findAllByRole('button', { name: /delete/i });
expect(delete_btns_2.length).toBe(1);
const no_btn_1 = screen.getByRole('button', { name: /no/i });
const no_btn_1 = screen.getByRole('button', { name: /cancel/i });
expect(no_btn_1).toBeInTheDocument();

fireEvent.click(no_btn_1);
expect(no_btn_1).not.toBeInTheDocument();
await waitFor(() => {
expect(no_btn_1).not.toBeInTheDocument();
});

const delete_btns_3 = await screen.findAllByRole('button', { name: /delete/i });
expect(delete_btns_3.length).toBe(2);
const delete_btns_2 = await screen.findAllByTestId('dt_token_delete_icon');
expect(delete_btns_2.length).toBe(2);

fireEvent.click(delete_btns_3[0]);
const yes_btn_1 = screen.getByRole('button', { name: /yes/i });
fireEvent.click(delete_btns_2[0]);
const yes_btn_1 = screen.getByRole('button', { name: /yes, delete/i });
expect(yes_btn_1).toBeInTheDocument();

fireEvent.click(yes_btn_1);
const deleteToken = mock_props.ws.authorized.apiToken;
expect(deleteToken).toHaveBeenCalled();
const delete_btns_4 = await screen.findAllByRole('button', { name: /delete/i });
expect(delete_btns_4.length).toBe(1);
await waitFor(() => {
expect(yes_btn_1).not.toBeInTheDocument();
});
});

it('should trigger hide/unhide icon and trigger copy icon, should show dialog only for admin scope', async () => {
jest.useFakeTimers();

const warning_msg =
'Be careful who you share this token with. Anyone with this token can perform the following actions on your account behalf';

document.execCommand = jest.fn();

getPropertyValue.mockReturnValue([
{
display_name: 'First test token',
last_used: '',
scopes: ['Read', 'Trade'],
token: 'FirstTokenID',
valid_for_ip: '',
},
{
display_name: 'Second test token',
last_used: '',
scopes: ['Read', 'Trade', 'Admin'],
token: 'SecondTokenID',
valid_for_ip: '',
},
]);

render(<ApiToken {...mock_props} />);

expect(await screen.findByText('First test token')).toBeInTheDocument();
expect(screen.queryByText('FirstTokenID')).not.toBeInTheDocument();

const toggle_visibility_btns = await screen.findAllByTestId('dt_toggle_visibility_icon');
expect(toggle_visibility_btns.length).toBe(2);

fireEvent.click(toggle_visibility_btns[0]);
expect(screen.getByText('FirstTokenID')).toBeInTheDocument();

fireEvent.click(toggle_visibility_btns[1]);
expect(screen.getByText('SecondTokenID')).toBeInTheDocument();

const copy_btns_1 = await screen.findAllByTestId('dt_copy_token_icon');
expect(copy_btns_1.length).toBe(2);

fireEvent.click(copy_btns_1[0]);
expect(screen.queryByText(warning_msg)).not.toBeInTheDocument();
expect(await screen.findByTestId('dt_token_copied_icon')).toBeInTheDocument();

act(() => jest.advanceTimersByTime(2100));
expect(screen.queryByTestId('dt_token_copied_icon')).not.toBeInTheDocument();

fireEvent.click(copy_btns_1[1]);
expect(await screen.findByText(warning_msg)).toBeInTheDocument();

expect(document.execCommand).toHaveBeenCalledTimes(1);

const ok_btn = screen.getByRole('button', { name: /ok/i });
expect(ok_btn).toBeInTheDocument();

fireEvent.click(ok_btn);
expect(await screen.findByTestId('dt_token_copied_icon')).toBeInTheDocument();
const copy_btns_2 = await screen.findAllByTestId('dt_copy_token_icon');
expect(copy_btns_2.length).toBe(1);

fireEvent.click(delete_btns_4[0]);
const no_btn_2 = screen.getByRole('button', { name: /no/i });
expect(no_btn_2).toBeInTheDocument();
const yes_btn_2 = screen.getByRole('button', { name: /yes/i });
expect(yes_btn_2).toBeInTheDocument();
act(() => jest.advanceTimersByTime(2100));
expect(screen.queryByTestId('dt_token_copied_icon')).not.toBeInTheDocument();

act(() => jest.advanceTimersByTime(10000));
expect(document.execCommand).toHaveBeenCalledTimes(2);

expect(no_btn_2).not.toBeInTheDocument();
expect(yes_btn_2).not.toBeInTheDocument();
jest.clearAllMocks();
});

it('should render created tokens for mobile', async () => {
Expand Down Expand Up @@ -287,14 +365,11 @@ describe('<ApiToken/>', () => {
expect((await screen.findAllByText('Name')).length).toBe(3);
expect((await screen.findAllByText('Last Used')).length).toBe(3);
expect((await screen.findAllByText('Token')).length).toBe(3);
expect((await screen.findAllByText('Scope')).length).toBe(3);
expect((await screen.findAllByText('Scopes')).length).toBe(3);
expect(await screen.findByText('First test token')).toBeInTheDocument();
expect(await screen.findByText('Second test token')).toBeInTheDocument();
expect(await screen.findByText('SecondTokenID')).toBeInTheDocument();
expect(screen.queryByText('Action')).not.toBeInTheDocument();
expect(screen.queryByText('Scopes')).not.toBeInTheDocument();
const all_scopes = await screen.findAllByText('All');
expect(all_scopes.length).toBe(1);
expect(screen.queryByText('SecondTokenID')).not.toBeInTheDocument();
const never_used = await screen.findAllByText('Never');
expect(never_used.length).toBe(2);
});
Expand Down
8 changes: 5 additions & 3 deletions packages/account/src/Components/api-token/api-token-card.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import * as React from 'react';
import React from 'react';
import { Field } from 'formik';
import { CompositeCheckbox } from '@deriv/components';

const ApiTokenCard = ({ name, value, display_name, description, setFieldValue }) => {
const ApiTokenCard = ({ name, value, display_name, description, setFieldValue, children }) => {
return (
<Field name={name}>
{({ field }) => (
Expand All @@ -15,7 +15,9 @@ const ApiTokenCard = ({ name, value, display_name, description, setFieldValue })
defaultChecked={value}
label={display_name}
description={description}
/>
>
{children}
</CompositeCheckbox>
)}
</Field>
);
Expand Down
Loading

0 comments on commit 92bff52

Please sign in to comment.