Skip to content

Commit

Permalink
[BOT]maryia/BOT-1981/feat: Add a "What's new" section to the dashboar… (
Browse files Browse the repository at this point in the history
deriv-com#16577)

* [BOT]maryia/BOT-1981/feat: Add a "What's new" section to the dashboard to promote Accumulators (deriv-com#16369)

* feat: announcement components

* refactor: announcement config, make accounce dialog reusable

* feat: make redirect and show block accumulator

* feat: show indicator updated upon clicking on announcements

* refactor: separate an announcement component

* feat: add saving to local storage, refactor the code

* chore: fix sonarcloud issues

* chore: fix sonarcloud issues(2)

* chore: fix sonarcloud issues(3)

* feat: redirect to default strategy with accumulator upon clicking "try now" button

* feat: redirect to default strategy with accumulator upon clicking "try now" button

* refactor: click on announce button

* feat: add video for accumulator feature on tutorial page

* chore: simplify access to the context of the DOM element

* test: announcement component

* test: announcement-dialog component

* test: announcements component

* chore: add cursor for the button

* chore: remove temporary other announcements except of accumulator feature

* refactor: styles and remove unused import

* chore: use global colors

* chore: rename names of the tests

* chore: change colors as per global colors

* refactor: minor things

* chore: remove UserGuide component and test

* chore: remove dependency

* chore: add @deriv/quill-icons to package.json

* chore: replace .then() to await waitFor

* chore: remove some code

* chore: change color to global color that support dark and light mode

* chore: refactor implementation, rename variables

* refactor: announcements component, configs and helper functions

* fix: sonar cloud issues

* fix: test cases

* fix: The icon and texts are not aligned as per design

* fix: The cta size is different compared to design

* fix: text indent

* refactor: announcement-dialog

* fix: styles announcement-dialog

* style: improve

* refactor: improvement accourding to comments (deriv-com#16603)

* feat: adapt Notifications component (deriv-com#16608)

* refactor: improvement accourding to comments

* feat: adapt Notifications component

* chore: rename prop of notifications

* chore: rename prop of notifications (deriv-com#16658)

* chore: renaming child of content from content to content_item

* chore: split .notifications_wrapper as per SASS convention

* chore: make the same everywhere React.useState( way

* chore: rename stored_notifications to read_announcements_map

* chore: rename temp_data to updated_local_storage_data

* chore: rename getButtonAction to performButtonAction

* chore: update the version of deriv-com/ui

* fix: the issue after update the version in dtrader

* fix: provide the notifications component with new mandatory prop loadMoreFunction

* chore: package-lock.json

* chore: update version of deriv-com/ui

* fix: remove loadMoreFunction prop

* refactor: method to calc amount active announce, state for it

* chore: add wrapper arrow function for handleRedirect method

* fix: Unable to see the pop up on tab view

* chore: add missed dependency, add eslint comments

* fix: modal width on tablet

* refactor: improve styles as per design on mobile version

* chore: update the date for accumulator announce

* chore: merge master(part2)
  • Loading branch information
maryia-matskevich-deriv authored Sep 18, 2024
1 parent 388e5ee commit 1b13e98
Show file tree
Hide file tree
Showing 29 changed files with 1,049 additions and 107 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@
"typescript": "^4.6.3",
"webpack": "^5.81.0"
}
}
}
2 changes: 1 addition & 1 deletion packages/appstore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@
"webpack-bundle-analyzer": "^4.3.0",
"webpack-cli": "^4.7.2"
}
}
}
2 changes: 2 additions & 0 deletions packages/bot-web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"webpack-cli": "^4.7.2"
},
"dependencies": {
"@deriv-com/ui": "1.35.0",
"@deriv/api": "^1.0.0",
"@deriv/api-types": "1.0.172",
"@deriv/bot-skeleton": "^1.0.0",
Expand All @@ -80,6 +81,7 @@
"@deriv/shared": "^1.0.0",
"@deriv/stores": "^1.0.0",
"@deriv/translations": "^1.0.0",
"@deriv/quill-icons": "1.23.3",
"blockly": "^10.4.3",
"@testing-library/user-event": "^13.5.0",
"@types/react-router-dom": "^5.1.6",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { mockStore, StoreProvider } from '@deriv/stores';
import { render, screen, waitFor } from '@testing-library/react';
import { mock_ws } from 'Utils/mock';
import RootStore from 'Stores/index';
import { DBotStoreProvider, mockDBotStore } from 'Stores/useDBotStore';
import userEvent from '@testing-library/user-event';
import AnnouncementDialog from '../announcement-dialog';
import { ANNOUNCEMENTS } from '../config';

jest.mock('@deriv/bot-skeleton/src/scratch/dbot', () => jest.fn());

const mocked_props = {
announcement: ANNOUNCEMENTS.ACCUMULATOR_ANNOUNCE.announcement,
is_announce_dialog_open: true,
setIsAnnounceDialogOpen: jest.fn(),
handleOnConfirm: jest.fn(),
handleOnCancel: jest.fn(),
};

describe('AnnouncementDialog', () => {
let wrapper: ({ children }: { children: JSX.Element }) => JSX.Element, mock_DBot_store: RootStore | undefined;
const mock_store = mockStore({});

beforeAll(() => {
mock_DBot_store = mockDBotStore(mock_store, mock_ws);

wrapper = ({ children }: { children: JSX.Element }) => (
<StoreProvider store={mock_store}>
<DBotStoreProvider ws={mock_ws} mock={mock_DBot_store}>
{children}
</DBotStoreProvider>
</StoreProvider>
);
});

it('should trigger the handleOnConfirm() function, when "Try now" button is clicked.', async () => {
render(<AnnouncementDialog {...mocked_props} />, { wrapper });
const buttonConfirm = screen.getByRole('button', { name: /Try now/i });
userEvent.click(buttonConfirm);

await waitFor(() => {
expect(mocked_props.handleOnConfirm).toHaveBeenCalled();
});
});

it('should trigger the handleOnCancel() function, when "Learn more" button is clicked.', async () => {
render(<AnnouncementDialog {...mocked_props} />, { wrapper });
const buttonCancel = screen.getByRole('button', { name: /Learn more/i });
userEvent.click(buttonCancel);

await waitFor(() => {
expect(mocked_props.handleOnCancel).toHaveBeenCalled();
});
});

it('should trigger the setIsAnnounceDialogOpen() function, when the icon cross button is clicked.', async () => {
const { container } = render(<AnnouncementDialog {...mocked_props} />, { wrapper });

// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container
const close_button = container.querySelector('.dc-dialog__header--close');

expect(close_button).toBeInTheDocument();

userEvent.click(close_button);

await waitFor(() => {
expect(mocked_props.setIsAnnounceDialogOpen).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { mockStore, StoreProvider } from '@deriv/stores';
import { render, screen, waitFor } from '@testing-library/react';
import { mock_ws } from 'Utils/mock';
import RootStore from 'Stores/index';
import { DBotStoreProvider, mockDBotStore } from 'Stores/useDBotStore';
import { Notifications as Announcement } from '@deriv-com/ui';
import userEvent from '@testing-library/user-event';

jest.mock('@deriv/bot-skeleton/src/scratch/dbot', () => jest.fn());

const announcements = [
{
icon: 'Icon',
title: 'Title1',
message: 'Message1',
buttonAction: () => jest.fn(),
actionText: '',
},
{
icon: 'Icon',
title: 'Title2',
message: 'Message2',
buttonAction: () => jest.fn(),
actionText: '',
},
];

const mock_component_config = {
clearButtonText: 'Mark all as read',
modalTitle: 'Announcement',
noNotificationsMessage: 'No announcements MESSAGE',
noNotificationsTitle: 'No announcements',
};

describe('Announcement', () => {
let wrapper: ({ children }: { children: JSX.Element }) => JSX.Element, mock_DBot_store: RootStore | undefined;
const mock_store = mockStore({});

beforeAll(() => {
mock_DBot_store = mockDBotStore(mock_store, mock_ws);

wrapper = ({ children }: { children: JSX.Element }) => (
<StoreProvider store={mock_store}>
<DBotStoreProvider ws={mock_ws} mock={mock_DBot_store}>
{children}
</DBotStoreProvider>
</StoreProvider>
);
});

it('should render the Announcement component and upon clicking "Mark all as read" button should trigger clearNotificationsCallback() function.', async () => {
const mockClearNotificationsCallback = jest.fn();
render(
<Announcement
componentConfig={mock_component_config}
notifications={announcements}
clearNotificationsCallback={mockClearNotificationsCallback}
setIsOpen={() => jest.fn()}
isOpen
/>,
{ wrapper }
);
const button = screen.getByRole('button', { name: /Mark all as read/i });
userEvent.click(button);

await waitFor(() => {
expect(mockClearNotificationsCallback).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React from 'react';
import { mockStore, StoreProvider } from '@deriv/stores';
import { render, screen, waitFor } from '@testing-library/react';
import { mock_ws } from 'Utils/mock';
import RootStore from 'Stores/index';
import { DBotStoreProvider, mockDBotStore } from 'Stores/useDBotStore';
import Announcements from '../announcements';
import userEvent from '@testing-library/user-event';
import { DBOT_TABS } from 'Constants/bot-contents';
import { BOT_ANNOUNCEMENTS_LIST } from '../config';

jest.mock('@deriv/bot-skeleton/src/scratch/dbot', () => jest.fn());
jest.mock('@deriv/bot-skeleton/src/scratch/xml/main.xml', () => '<xml>sample</xml>');
window.Blockly = {
utils: {
xml: {
textToDom: (xmlString: string) => {
const parser = new DOMParser();
return parser.parseFromString(xmlString, 'text/xml');
},
},
},
Xml: { domToText: () => ({}) },
};

const mockHandleTabChange = jest.fn();

describe('Announcements', () => {
let wrapper: ({ children }: { children: JSX.Element }) => JSX.Element, mock_DBot_store: RootStore | undefined;
const mock_store = mockStore({});

beforeAll(() => {
mock_DBot_store = mockDBotStore(mock_store, mock_ws);

wrapper = ({ children }: { children: JSX.Element }) => (
<StoreProvider store={mock_store}>
<DBotStoreProvider ws={mock_ws} mock={mock_DBot_store}>
{children}
</DBotStoreProvider>
</StoreProvider>
);
});

it('should decrease the indicator count and remove it, the list of announcements should be displayed, and redirect to tutorial page upon clicking on the announcement item.', async () => {
const { container } = render(<Announcements handleTabChange={mockHandleTabChange} is_mobile={true} />, {
wrapper,
});
const button = screen.getByTestId('btn-announcements');
userEvent.click(button);

await waitFor(() => {
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container
const notification_button = container.querySelector('.notification__button');

expect(notification_button).toBeInTheDocument();

userEvent.click(notification_button);
});
await waitFor(() => {
expect(screen.queryByTestId('announcements__amount')).not.toBeInTheDocument();

const button_cancel = screen.getByRole('button', { name: /Learn more/i });
userEvent.click(button_cancel);
});
await waitFor(() => {
expect(mock_DBot_store?.dashboard.setActiveTab(DBOT_TABS.TUTORIAL));
});
});

it('should decrease the indicator count and remove it, the list of announcements should be displayed, and redirect to bot builder page upon clicking on the accumulator announcement item.', async () => {
const { container } = render(<Announcements handleTabChange={mockHandleTabChange} is_mobile={true} />, {
wrapper,
});
const button = screen.getByTestId('btn-announcements');
userEvent.click(button);

await waitFor(() => {
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container
const notification_button = container.querySelector('.notification__button');

expect(notification_button).toBeInTheDocument();

userEvent.click(notification_button);
});
await waitFor(() => {
expect(screen.queryByTestId('announcements__amount')).not.toBeInTheDocument();
const buttonConfirm = screen.getByRole('button', { name: /Try now/i });
userEvent.click(buttonConfirm);
});
await waitFor(() => {
expect(mock_DBot_store?.dashboard.setActiveTab(DBOT_TABS.BOT_BUILDER));
});
});

it('should disappear the announcements indicator, when the "Mark All as Read" button is clicked.', async () => {
render(<Announcements handleTabChange={mockHandleTabChange} is_mobile={false} />, {
wrapper,
});

const button_announcements = screen.getByTestId('btn-announcements');
userEvent.click(button_announcements);

const button_mark_all_as_read = screen.getByRole('button', { name: /Mark all as read/i });
userEvent.click(button_mark_all_as_read);

await waitFor(() => {
expect(screen.queryByTestId('announcements__amount')).not.toBeInTheDocument();
});
});

it('should display all active announcements when bot-announcements has already existed in local storage.', () => {
localStorage?.setItem('bot-announcements', JSON.stringify({ ...BOT_ANNOUNCEMENTS_LIST }));
render(<Announcements handleTabChange={mockHandleTabChange} is_mobile={false} />, {
wrapper,
});

const button = screen.getByTestId('btn-announcements');
userEvent.click(button);

expect(screen.getByTestId('announcements__amount')).toHaveTextContent(`${BOT_ANNOUNCEMENTS_LIST.length}`);
});
});
Loading

0 comments on commit 1b13e98

Please sign in to comment.