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

Maryia/83311/Refactoring, tests, TS migration #50

666 changes: 0 additions & 666 deletions packages/shared/src/utils/helpers/dummy_accumulators_data.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/shared/src/utils/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ export * from './market-underlying';
export * from './portfolio-notifications';
export * from './start-date';
export * from './validation-rules';
export * from './dummy_accumulators_data';
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import { fireEvent, render, screen, within } from '@testing-library/react';
import { AccumulatorsStatsManualModal } from '../accumulators-stats-manual-modal';

jest.mock('@deriv/components', () => {
const original_module = jest.requireActual('@deriv/components');
const Modal = jest.fn(
props =>
props.is_open && (
<div data-testid='modal'>
<h3>{props.title}</h3>
<div onClick={props.toggleModal}>IcCross</div>
{props.children}
</div>
)
);
Modal.Body = jest.fn(props => <div> {props.children} </div>);
return {
...original_module,
Icon: jest.fn(props => <div onClick={props.onClick}>{props.icon}</div>),
Modal,
};
});

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
getUrlBase: jest.fn(() => 'video_src.mp4'),
}));

describe('AccumulatorsStatsManualModal', () => {
const modal_root_el = document.createElement('div');
modal_root_el.setAttribute('id', 'modal_root');
document.body.appendChild(modal_root_el);

let props;
beforeEach(() => {
props = {
title: 'Stats',
icon_classname: 'info',
is_manual_open: false,
toggleManual: jest.fn(() => {
props.is_manual_open = !props.is_manual_open;
}),
};
});

it('should open when info icon (IcInfoOutline) is clicked', () => {
const { rerender } = render(<AccumulatorsStatsManualModal {...props} />);
const info_icon = screen.getByText('IcInfoOutline');
fireEvent.click(info_icon);
expect(props.toggleManual).toBeCalled();
expect(props.is_manual_open).toBeTruthy();

rerender(<AccumulatorsStatsManualModal {...props} />);
expect(screen.getByRole('heading', '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);
expect(props.toggleManual).toBeCalled();
expect(props.is_manual_open).toBeFalsy();

rerender(<AccumulatorsStatsManualModal {...props} />);
expect(screen.queryByTestId('modal')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
isDesktop: jest.fn(),
isMobile: jest.fn(),
getUrlBase: jest.fn(() => 'image_src.svg'),
getUrlBase: jest.fn(() => 'video_src.mp4'),
}));

describe('AccumulatorsStats', () => {
const modal_root_el = document.createElement('div');
modal_root_el.setAttribute('id', 'modal_root');
document.body.appendChild(modal_root_el);
const ticks_history = mock_connect_props.ticks_history_stats.ticks_stayed_in;

beforeEach(() => {
isMobile.mockReturnValue(false);
Expand All @@ -42,9 +40,11 @@ describe('AccumulatorsStats', () => {
expect(container.querySelector('.accordion-toggle-arrow')).not.toBeInTheDocument();
});
it('should show manual after info icon is clicked', () => {
const { container } = render(<AccumulatorsStats />);
const { container } = render(<AccumulatorsStats />, {
container: document.body.appendChild(modal_root_el),
});
fireEvent.click(container.querySelector('.info'));
expect(screen.getByTestId('dt_accumulators_stats_manual')).toBeInTheDocument();
expect(screen.getByTestId('dt_accumulators_stats_manual_video')).toBeInTheDocument();
});
it('should render partial history values (tick counters) when initially collapsed in desktop', () => {
render(<AccumulatorsStats />);
Expand All @@ -68,7 +68,9 @@ describe('AccumulatorsStats', () => {
it('should show MobileDialog with full "Stay in history" in mobile when accordion_toggle_arrow is clicked', () => {
isMobile.mockReturnValue(true);
isDesktop.mockReturnValue(false);
const { container } = render(<AccumulatorsStats />);
const { container } = render(<AccumulatorsStats />, {
container: document.body.appendChild(modal_root_el),
});
expect(screen.getAllByTestId('dt_accu_stats_history_counter').length).toEqual(ROW_SIZES.MOBILE_COLLAPSED);

fireEvent.click(container.querySelector('.accordion-toggle-arrow'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'Sass/app/modules/contract/accumulators-stats.scss';

const AccumulatorsStatsManualModal = ({ title, icon_classname, is_manual_open, toggleManual }) => {
const is_mobile = isMobile();
// memoize video sources and open the modal only after we get them to avoid showing half-empty modal
// memoize file paths for videos and open the modal only after we get them
const getVideoSource = React.useCallback(
extension => {
return getUrlBase(
Expand All @@ -16,23 +16,32 @@ const AccumulatorsStatsManualModal = ({ title, icon_classname, is_manual_open, t
},
[is_mobile]
);
const mp4_src = React.useMemo(() => getVideoSource('mp4'), [getVideoSource]);
const webm_src = React.useMemo(() => getVideoSource('webm'), [getVideoSource]);

return (
<React.Fragment>
<Icon icon='IcInfoOutline' onClick={toggleManual} size={16} className={icon_classname} />
<Modal
is_open={is_manual_open && !!getVideoSource('mp4') && !!getVideoSource('webm')}
is_open={is_manual_open && !!mp4_src && !!webm_src}
should_header_stick_body={false}
title={title}
toggleModal={toggleManual}
width={is_mobile ? '328px' : '596px'}
className='accumulators-stats-manual-modal'
>
<Modal.Body className='accumulators-stats-modal-body'>
<div className='accumulators-stats-modal-body__video' data-testid='dt_accumulators_stats_manual'>
<video width={is_mobile ? 296 : 563} autoPlay loop playsInline>
<div className='accumulators-stats-modal-body__video'>
<video
width={is_mobile ? 296 : 563}
autoPlay
loop
playsInline
data-testid='dt_accumulators_stats_manual_video'
>
{/* a browser will select a source with extension it recognizes */}
<source src={getVideoSource('mp4')} type='video/mp4' />
<source src={getVideoSource('webm')} type='video/webm' />
<source src={mp4_src} type='video/mp4' />
<source src={webm_src} type='video/webm' />
{localize('Unfortunately, your browser does not support the video.')}
</video>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { filterByContractType } from 'App/Components/Elements/PositionsDrawer/helpers/positions-helper.js';
import PropTypes from 'prop-types';
import React from 'react';
import AccumulatorsProfitLossTooltip from './accumulators-profit-loss-tooltip.jsx';
import CurrentSpotHighlighter from './current-spot-highlighter.jsx';

const AccumulatorsChartElements = ({
all_positions,
current_symbol_spot,
current_symbol_spot_time,
is_stats_highlighted,
last_contract_info,
symbol,
}) => {
const accumulators_positions = all_positions.filter(
p =>
p.contract_info &&
symbol === p.contract_info.underlying &&
filterByContractType(p.contract_info, 'accumulator')
);
const should_highlight_tick_without_contract = current_symbol_spot_time && is_stats_highlighted;
const should_highlight_contract_tick =
last_contract_info?.status === 'lost' && current_symbol_spot_time === last_contract_info?.exit_tick_time;
const should_highlight_tick = should_highlight_tick_without_contract || should_highlight_contract_tick;
const current_spot = should_highlight_contract_tick ? last_contract_info?.exit_tick : current_symbol_spot;
const current_spot_time = should_highlight_contract_tick
? last_contract_info?.exit_tick_time
: current_symbol_spot_time;

return (
<>
{accumulators_positions.length &&
accumulators_positions.map(({ contract_info }) => (
<AccumulatorsProfitLossTooltip key={contract_info.contract_id} {...contract_info} />
))}
{should_highlight_tick && (
<CurrentSpotHighlighter current_spot={current_spot} current_spot_time={current_spot_time} />
)}
</>
);
};

AccumulatorsChartElements.propTypes = {
all_positions: PropTypes.array,
current_symbol_spot: PropTypes.number,
current_symbol_spot_time: PropTypes.number,
is_stats_highlighted: PropTypes.bool,
last_contract_info: PropTypes.object,
symbol: PropTypes.string,
};

export default React.memo(AccumulatorsChartElements);
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import React from 'react';
import { expect } from 'chai';
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { render, screen } from '@testing-library/react';
import PurchaseButtonsOverlay from '../purchase-buttons-overlay.jsx';

configure({ adapter: new Adapter() });

describe('PurchaseButtonsOverlay', () => {
const message = 'You can only purchase one contract at a time';

it('should render <PurchaseButtonsOverlay /> component', () => {
const wrapper = mount(<PurchaseButtonsOverlay message={message} />);
const has_correct_message = wrapper.contains(message);
expect(has_correct_message).to.equal(true);
it('should render with a correct message', () => {
render(<PurchaseButtonsOverlay message={message} />);
expect(screen.getByText(message)).toBeInTheDocument();
});

it('should have purchase-buttons-overlay__one-button class when is_to_cover_one_button prop is passed', () => {
const wrapper = mount(<PurchaseButtonsOverlay message={message} is_to_cover_one_button />);
expect(wrapper.render()[0].attribs.class).to.match(/__one-button/);
render(<PurchaseButtonsOverlay message={message} is_to_cover_one_button />);
expect(screen.getByTestId('dt_purchase_button_overlay')).toHaveClass('purchase-buttons-overlay__one-button');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const PurchaseButtonsOverlay = ({ is_to_cover_one_button = false, message }) =>
const desktop_text_size = is_to_cover_one_button ? 'xxs' : 'xs';
return (
<div
data-testid='dt_purchase_button_overlay'
className={classNames('purchase-buttons-overlay', {
'purchase-buttons-overlay__one-button': !isMobile() && is_to_cover_one_button,
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Accumulator.propTypes = {
accumulator_range_list: MobxPropTypes.arrayOrObservableArray,
growth_rate: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
onChange: PropTypes.func,
tick_size_barrier: PropTypes.number,
};

export default connect(({ modules }) => ({
Expand Down
30 changes: 12 additions & 18 deletions packages/trader/src/Modules/Trading/Containers/trade.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import Test from './test.jsx';
import { ChartBottomWidgets, ChartTopWidgets, DigitsWidget } from './chart-widgets.jsx';
import FormLayout from '../Components/Form/form-layout.jsx';
import AllMarkers from '../../SmartChart/Components/all-markers.jsx';
import AccumulatorsProfitLossTooltip from '../../SmartChart/Components/Markers/accumulators-profit-loss-tooltip.jsx';
import CurrentSpotHighlighter from '../../SmartChart/Components/Markers/current-spot-highlighter.jsx';
import AccumulatorsChartElements from '../../SmartChart/Components/Markers/accumulators-chart-elements.jsx';
import ToolbarWidgets from '../../SmartChart/Components/toolbar-widgets.jsx';

const BottomWidgetsMobile = ({ tick, digits, setTick, setDigits }) => {
Expand Down Expand Up @@ -260,7 +259,6 @@ export default connect(({ client, common, modules, ui }) => ({
/* eslint-disable */
import { SmartChart } from 'Modules/SmartChart';
import classNames from 'classnames';
import { filterByContractType } from 'App/Components/Elements/PositionsDrawer/helpers/positions-helper.js';

const SmartChartWithRef = React.forwardRef((props, ref) => <SmartChart innerRef={ref} {...props} />);

Expand Down Expand Up @@ -301,6 +299,7 @@ const Chart = props => {
chartStateChange,
current_symbol_spot,
current_symbol_spot_time,
last_contract,
ticks_history_stats,
exportLayout,
extra_barriers = [],
Expand Down Expand Up @@ -353,13 +352,6 @@ const Chart = props => {

if (!symbol || active_symbols.length === 0) return null;

const accumulators_positions = all_positions.filter(
p =>
p.contract_info &&
symbol === p.contract_info.underlying &&
filterByContractType(p.contract_info, 'accumulator')
);

return (
<SmartChartWithRef
ref={charts_ref}
Expand Down Expand Up @@ -410,14 +402,14 @@ const Chart = props => {
}}
>
<ChartMarkers />
{is_accumulator &&
accumulators_positions.map(({ contract_info }) => (
<AccumulatorsProfitLossTooltip key={contract_info.contract_id} {...contract_info} />
))}
{is_accumulator && current_symbol_spot_time && ticks_history_stats?.ticks_stayed_in?.[0] === 0 && (
<CurrentSpotHighlighter
current_spot={current_symbol_spot}
current_spot_time={current_symbol_spot_time}
{is_accumulator && (
<AccumulatorsChartElements
all_positions={all_positions}
current_symbol_spot={current_symbol_spot}
current_symbol_spot_time={current_symbol_spot_time}
is_stats_highlighted={ticks_history_stats?.ticks_stayed_in?.[0] === 0}
last_contract_info={last_contract?.contract_info}
symbol={symbol}
/>
)}
</SmartChartWithRef>
Expand All @@ -441,6 +433,7 @@ Chart.propTypes = {
is_trade_enabled: PropTypes.bool,
is_socket_opened: PropTypes.bool,
has_alternative_source: PropTypes.bool,
last_contract: PropTypes.object,
main_barrier: PropTypes.any,
refToAddTick: PropTypes.func,
setChartStatus: PropTypes.func,
Expand Down Expand Up @@ -474,6 +467,7 @@ const ChartTrade = connect(({ modules, ui, common, contract_trade, portfolio })
last_contract: {
is_digit_contract: contract_trade.last_contract.is_digit_contract,
is_ended: contract_trade.last_contract.is_ended,
contract_info: contract_trade.last_contract.contract_info,
},
is_trade_enabled: modules.trade.is_trade_enabled,
main_barrier: modules.trade.main_barrier_flattened,
Expand Down
Loading