Skip to content

Commit

Permalink
Henry/dtra 77/ts migration test coverage accu components (binary-com#…
Browse files Browse the repository at this point in the history
…8852)

* test: ts-migration and test coverage for accumulators chart elements

* fix: automate test runners errors

* fix: automate test runners errors

* test: TS migrated and update test coverage for existing accu components

* test: ts-migration and test coverage for existing accumulators components

* fix: codecov errors

* fix: resolve comments

* fix: resolve comments

* fix: circle ci error

* fix: resolve comments

* fix: circleCI errors

* fix: CircleCI issues

* test: add test for accumulator trade description

* fix: remove unnecessary import

* fix: remove use of usestore types

* fix: remove mockstore and types from typests

* fix: circle ci issues

* fix: circle ci issues

* fix: switch to generics

* refactor: cleanup code

* fix: change code order

* test: ts migration and test coverage of accumulators components

* test: add test cases and ts migration of remaining accu components

* fix: circleci issue

* fix: circlci

* fix: circlci

* fix: resolve comments

* fix: code smells

* fix: resolve comments

* fix: resolve comments

* fix: circlci

* fix: code smells

* fix: circleci

* fix: nit

* fix: codecov

* fix: switch to userevent

* fix: circleCI

* fix: circleCI

* fix: circleCi

* fix: resolve sonarcloud

* fix: remove unused imports

* fix: circle CI

* fix: make a prop optional

* fix: circleCI errors

* fix: circleCi test

* fix: remove extra space

* fix: duplicate mock props

* fix: circleCI

* fix: change file extension
  • Loading branch information
henry-deriv committed Sep 26, 2023
1 parent 47b88bd commit 9b7fc32
Show file tree
Hide file tree
Showing 40 changed files with 526 additions and 242 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import AccumulatorCardBody from '../accumulator-card-body';

type TAccumulatorCardBody = React.ComponentProps<typeof AccumulatorCardBody>;

describe('<AccumulatorCardBody />', () => {
const mock_props: TAccumulatorCardBody = {
contract_info: {
buy_price: 123,
sell_price: 234,
profit: 111,
contract_id: 12345,
is_valid_to_sell: 1,
status: 'sold',
is_settleable: 1,
is_expired: 1,
},
contract_update: {
take_profit: {
order_amount: 300,
},
},
getCardLabels: () => ({
CURRENT_STAKE: 'Current stake:',
INITIAL_STAKE: 'Initial stake:',
TAKE_PROFIT: 'Take profit:',
TOTAL_PROFIT_LOSS: 'Total profit/loss:',
}),
is_sold: 1,
status: 'profit',
currency: 'USD',
};
it('should display all contract card items, label, and values', () => {
render(<AccumulatorCardBody {...mock_props} />);
expect(screen.getByText('Initial stake:')).toBeInTheDocument();
expect(screen.getByText('123.00')).toBeInTheDocument();
expect(screen.getByText('Current stake:')).toBeInTheDocument();
expect(screen.getByText('234.00')).toBeInTheDocument();
expect(screen.getByText('Total profit/loss:')).toBeInTheDocument();
expect(screen.getByText('111.00')).toBeInTheDocument();
expect(screen.getByText('Take profit:')).toBeInTheDocument();
expect(screen.getByText('300.00')).toBeInTheDocument();
});

it('should display Take profit: label and - as value when take_profit is not available', () => {
if (mock_props?.contract_update?.take_profit?.order_amount)
mock_props.contract_update.take_profit.order_amount = null;
render(<AccumulatorCardBody {...mock_props} />);
expect(screen.getByText('Take profit:')).toBeInTheDocument();
expect(screen.getByText('-')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import { isCryptocurrency, getLimitOrderAmount, isValidToSell } from '@deriv/shared';
import { TContractInfo } from '@deriv/shared/src/utils/contract/contract-types';
import ContractCardItem from './contract-card-item';
import ToggleCardDialog from './toggle-card-dialog';
import Icon from '../../icon';
import MobileWrapper from '../../mobile-wrapper';
import Money from '../../money';
import { ResultStatusIcon } from '../result-overlay/result-overlay';
import { ContractUpdate } from '@deriv/api-types';
import { TToastConfig } from '../../types/contract.types';
import { TGetCardLables } from '../../types/common.types';

type TAccumulatorCardBody = {
addToast: (toast_config: TToastConfig) => void;
connectWithContractUpdate?: React.ComponentProps<typeof ToggleCardDialog>['connectWithContractUpdate'];
contract_info: TContractInfo;
contract_update?: ContractUpdate;
currency: Required<TContractInfo>['currency'];
current_focus?: string | null;
error_message_alignment?: string;
getCardLabels: TGetCardLables;
getContractById: React.ComponentProps<typeof ToggleCardDialog>['getContractById'];
indicative?: number;
is_sold: boolean;
onMouseLeave: () => void;
removeToast: (toast_id: string) => void;
setCurrentFocus: (value: string) => void;
status?: string;
is_positions?: boolean;
};

const AccumulatorCardBody = ({
addToast,
Expand All @@ -26,11 +48,16 @@ const AccumulatorCardBody = ({
setCurrentFocus,
status,
is_positions,
}) => {
}: TAccumulatorCardBody) => {
const { buy_price, profit, limit_order, sell_price } = contract_info;
const { take_profit } = getLimitOrderAmount(contract_update || limit_order);
const is_valid_to_sell = isValidToSell(contract_info);
const { CURRENT_STAKE, INITIAL_STAKE, TAKE_PROFIT, TOTAL_PROFIT_LOSS } = getCardLabels();
let is_won, is_loss;
if (profit) {
is_won = +profit > 0;
is_loss = +profit < 0;
}

return (
<React.Fragment>
Expand All @@ -41,8 +68,8 @@ const AccumulatorCardBody = ({
<ContractCardItem header={CURRENT_STAKE} className='dc-contract-card__current-stake'>
<div
className={classNames({
'dc-contract-card--profit': +profit > 0,
'dc-contract-card--loss': +profit < 0,
'dc-contract-card--profit': is_won,
'dc-contract-card--loss': is_loss,
})}
>
<Money amount={sell_price || indicative} currency={currency} />
Expand All @@ -59,8 +86,8 @@ const AccumulatorCardBody = ({
<ContractCardItem
header={TOTAL_PROFIT_LOSS}
is_crypto={isCryptocurrency(currency)}
is_loss={+profit < 0}
is_won={+profit > 0}
is_loss={is_loss}
is_won={is_won}
>
<Money amount={profit} currency={currency} />
<div
Expand Down Expand Up @@ -99,31 +126,12 @@ const AccumulatorCardBody = ({
'dc-contract-card__status--accumulator-mobile-positions': is_positions,
})}
>
<ResultStatusIcon getCardLabels={getCardLabels} is_contract_won={+profit > 0} />
<ResultStatusIcon getCardLabels={getCardLabels} is_contract_won={is_won} />
</div>
</MobileWrapper>
)}
</React.Fragment>
);
};

AccumulatorCardBody.propTypes = {
addToast: PropTypes.func,
connectWithContractUpdate: PropTypes.func,
contract_info: PropTypes.object,
contract_update: PropTypes.object,
currency: PropTypes.string,
current_focus: PropTypes.string,
error_message_alignment: PropTypes.string,
getCardLabels: PropTypes.func,
getContractById: PropTypes.func,
indicative: PropTypes.number,
is_positions: PropTypes.bool,
is_sold: PropTypes.bool,
onMouseLeave: PropTypes.func,
removeToast: PropTypes.func,
setCurrentFocus: PropTypes.func,
status: PropTypes.string,
};

export default React.memo(AccumulatorCardBody);
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const ContractCardBody = ({
{...toggle_card_dialog_props}
/>
);
} else if (is_accumulator) {
} else if (is_accumulator && indicative !== null) {
card_body = (
<AccumulatorCardBody
contract_info={contract_info}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import Text from '../../text';

const TickCounterBar = ({ current_tick, label, max_ticks_duration }) => (
type TTickCounterBar = {
current_tick?: number;
label: string;
max_ticks_duration?: number;
};
const TickCounterBar = ({ current_tick, label, max_ticks_duration }: TTickCounterBar) => (
<div className='dc-tick-counter-bar__container'>
<div className='dc-tick-counter-bar__track'>
<Text size='xxs' weight='bold' className='dc-tick-counter-bar__text'>
Expand All @@ -12,10 +16,4 @@ const TickCounterBar = ({ current_tick, label, max_ticks_duration }) => (
</div>
);

TickCounterBar.propTypes = {
current_tick: PropTypes.number,
label: PropTypes.string,
max_ticks_duration: PropTypes.number,
};

export default React.memo(TickCounterBar);
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type TResultOverlayProps = {

type TResultStatusIcon = {
getCardLabels: TGetCardLables;
is_contract_won: boolean;
is_contract_won?: boolean;
};

export const ResultStatusIcon = ({ getCardLabels, is_contract_won }: TResultStatusIcon) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Div100vh from 'react-div-100vh';

type TDiv100vhContainer = {
id?: string;
height_offset: string;
height_offset?: string;
is_bypassed?: boolean;
is_disabled?: boolean;
max_height_offset?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/stores/src/mockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ const mock = (): TStores & { is_mock: boolean } => {
is_logged_in: false,
is_logging_in: false,
is_pending_proof_of_ownership: false,
is_switching: false,
is_single_currency: false,
is_switching: false,
is_tnc_needed: false,
is_trading_experience_incomplete: false,
is_virtual: false,
Expand Down
2 changes: 1 addition & 1 deletion packages/stores/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ type TClientStore = {
is_logging_in: boolean;
is_low_risk: boolean;
is_pending_proof_of_ownership: boolean;
is_switching: boolean;
is_single_currency: boolean;
is_switching: boolean;
is_tnc_needed: boolean;
is_trading_experience_incomplete: boolean;
is_virtual: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import AccumulatorTradeDescription from '../accumulator-trade-description';
import userEvent from '@testing-library/user-event';

describe('<AccumulatorTradeDescription />', () => {
it('Ensure content of component is rendered properly', () => {
render(<AccumulatorTradeDescription onClick={jest.fn()} />);
expect(
screen.getByText(
/Your stake will continue to grow as long as the current spot price remains within a specified/i
)
).toBeInTheDocument();
});
it('Ensure clicking on definition works', () => {
const onClick = jest.fn();
render(<AccumulatorTradeDescription onClick={onClick} />);
const glossary_definition = screen.getByText(/growth rate/i);
userEvent.click(glossary_definition);
expect(onClick).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import React from 'react';
import { fireEvent, render, screen, within } from '@testing-library/react';
import { render, screen, within } from '@testing-library/react';
import { AccumulatorsStatsManualModal } from '../accumulators-stats-manual-modal';
import userEvent from '@testing-library/user-event';

type TModal = React.ComponentType<{
children: React.ReactNode;
is_open: boolean;
title: string;
toggleModal: () => void;
}> & {
Body?: React.ComponentType<{
children: React.ReactNode;
}>;
};

jest.mock('@deriv/components', () => {
const original_module = jest.requireActual('@deriv/components');
const Modal = jest.fn(
({ children, is_open, title, toggleModal }) =>
is_open && (
<div data-testid='modal'>
<h3>{title}</h3>
<div onClick={toggleModal}>IcCross</div>
{children}
</div>
)
const Modal: TModal = jest.fn(({ children, is_open, title, toggleModal }) =>
is_open ? (
<div data-testid='modal'>
<h3>{title}</h3>
<div onClick={toggleModal}>IcCross</div>
{children}
</div>
) : null
);
Modal.Body = jest.fn(({ children }) => <div>{children}</div>);
return {
Expand All @@ -32,7 +43,7 @@ describe('AccumulatorsStatsManualModal', () => {
modal_root_el.setAttribute('id', 'modal_root');
document.body.appendChild(modal_root_el);

let props;
let props: React.ComponentProps<typeof AccumulatorsStatsManualModal>;
beforeEach(() => {
props = {
title: 'Stats',
Expand All @@ -47,20 +58,20 @@ describe('AccumulatorsStatsManualModal', () => {
it('should open when info icon (IcInfoOutline) is clicked', () => {
const { rerender } = render(<AccumulatorsStatsManualModal {...props} />);
const info_icon = screen.getByText('IcInfoOutline');
fireEvent.click(info_icon);
userEvent.click(info_icon);
expect(props.toggleManual).toBeCalled();
expect(props.is_manual_open).toBeTruthy();

rerender(<AccumulatorsStatsManualModal {...props} />);
expect(screen.getByRole('heading', 'Stats')).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Stats' })).toBeInTheDocument();
expect(screen.getByTestId('dt_accumulators_stats_manual_video')).toBeInTheDocument();
expect(screen.getByText(/stats show the history of consecutive tick counts/i)).toBeInTheDocument();
});
it('should close after close button (IcCross) is clicked in the modal', () => {
props.is_manual_open = true;
const { rerender } = render(<AccumulatorsStatsManualModal {...props} />);
const close_icon = within(screen.getByTestId('modal')).getByText('IcCross');
fireEvent.click(close_icon);
userEvent.click(close_icon);
expect(props.toggleManual).toBeCalled();
expect(props.is_manual_open).toBeFalsy();

Expand Down
Loading

0 comments on commit 9b7fc32

Please sign in to comment.