forked from binary-com/deriv-app
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DTRA / Vinu, Kate / DTRA-1670 / Onboarding Guide [DTrader-V2] (binary…
…-com#16589) * feat: add npm package, prepare local store and create a base modal for starting guide * feat: add guide container and tooltip component * refactor: tooltip componnet * refactor: set flag to trye on finish and styling * fix: close and skip functionality * feat: add the video * feat: add step 3 and inprove tooltip width * feat: add steps 3 5 6 and remove skip button * refactor: make guide modal reusable for positions page * refactor: add tests * feat: added step 4 for onboarding in dtrader v2 (#82) * feat: added step 4 for onboarding in dtrader v2 * fix: resolved code suggestion * fix: replaced pixel for scroll icon with quill token * refactor: update quill ui refactor onboarding guide functions and fix tests * fix: link console error * refactor: apply suggestions * chore: update quill --------- Co-authored-by: vinu-deriv <100689171+vinu-deriv@users.noreply.github.com>
- Loading branch information
1 parent
71a5dd7
commit 122e4d5
Showing
24 changed files
with
760 additions
and
26 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
packages/trader/src/AppV2/Components/OnboardingGuide/__tests__/guide-container.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { CallBackProps } from 'react-joyride'; | ||
import GuideContainer from '../guide-container'; | ||
|
||
jest.mock('react-joyride', () => ({ | ||
__esModule: true, | ||
default: jest.fn(({ callback }: { callback: (data: CallBackProps) => void }) => ( | ||
<div> | ||
<p>Joyride</p> | ||
<button onClick={() => callback({ status: 'finished' } as CallBackProps)} /> | ||
</div> | ||
)), | ||
STATUS: { SKIPPED: 'skipped', FINISHED: 'finished' }, | ||
})); | ||
|
||
const mock_props = { | ||
should_run: true, | ||
onFinishGuide: jest.fn(), | ||
}; | ||
|
||
describe('GuideContainer', () => { | ||
it('should render component', () => { | ||
render(<GuideContainer {...mock_props} />); | ||
|
||
expect(screen.getByText('Joyride')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should call onFinishGuide inside of callbackHandle if passed status is equal to "skipped" or "finished"', () => { | ||
render(<GuideContainer {...mock_props} />); | ||
userEvent.click(screen.getByRole('button')); | ||
|
||
expect(mock_props.onFinishGuide).toBeCalled(); | ||
}); | ||
}); |
47 changes: 47 additions & 0 deletions
47
packages/trader/src/AppV2/Components/OnboardingGuide/__tests__/guide-tooltip.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import GuideTooltip, { GuideTooltipProps } from '../guide-tooltip'; | ||
|
||
jest.mock('react-joyride', () => jest.fn(() => <div>Joyride</div>)); | ||
|
||
const mock_props = { | ||
isLastStep: false, | ||
primaryProps: { | ||
title: 'Title', | ||
}, | ||
skipProps: { | ||
title: 'Title', | ||
}, | ||
step: { | ||
title: 'Title', | ||
content: 'Step content', | ||
}, | ||
setStepIndex: jest.fn(), | ||
tooltipProps: {}, | ||
} as unknown as GuideTooltipProps; | ||
|
||
describe('GuideTooltip', () => { | ||
it('should render correct content for tooltip if isLastStep === false', () => { | ||
render(<GuideTooltip {...mock_props} />); | ||
|
||
expect(screen.getByText('Title')).toBeInTheDocument(); | ||
expect(screen.getByText('Step content')).toBeInTheDocument(); | ||
expect(screen.getByText('Next')).toBeInTheDocument(); | ||
expect(screen.queryByText('Done')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render correct content for tooltip if isLastStep === true', () => { | ||
render(<GuideTooltip {...mock_props} isLastStep={true} />); | ||
|
||
expect(screen.getByText('Title')).toBeInTheDocument(); | ||
expect(screen.getByText('Step content')).toBeInTheDocument(); | ||
expect(screen.getByText('Done')).toBeInTheDocument(); | ||
expect(screen.queryByText('Next')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render scroll icon if title of the step is scroll-icon', () => { | ||
mock_props.step.title = 'scroll-icon'; | ||
render(<GuideTooltip {...mock_props} isLastStep={true} />); | ||
expect(screen.getByText('Swipe up to see the chart')).toBeInTheDocument(); | ||
}); | ||
}); |
105 changes: 105 additions & 0 deletions
105
packages/trader/src/AppV2/Components/OnboardingGuide/__tests__/onboarding-guide.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import React from 'react'; | ||
import { render, screen, waitFor } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import OnboardingGuide from '../onboarding-guide'; | ||
|
||
const trading_modal_text = 'Welcome to the new Deriv Trader'; | ||
const positions_modal_text = 'View your positions'; | ||
const guide_container = 'GuideContainer'; | ||
|
||
jest.mock('../guide-container', () => | ||
jest.fn(({ should_run }: { should_run?: boolean }) => <div>{should_run && guide_container}</div>) | ||
); | ||
jest.mock('../onboarding-video', () => jest.fn(() => <div>OnboardingVideo</div>)); | ||
|
||
describe('OnboardingGuide', () => { | ||
beforeEach(() => { | ||
localStorage.clear(); | ||
}); | ||
|
||
it('should render Modal with correct content for trading page after 800ms after mounting', async () => { | ||
jest.useFakeTimers(); | ||
render(<OnboardingGuide />); | ||
|
||
await waitFor(() => jest.advanceTimersByTime(800)); | ||
|
||
expect(screen.getByText('OnboardingVideo')).toBeInTheDocument(); | ||
expect(screen.getByText(trading_modal_text)).toBeInTheDocument(); | ||
expect(screen.getByText("Let's begin")).toBeInTheDocument(); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
|
||
it('should render Modal with correct content for positions page after 800ms after mounting', async () => { | ||
jest.useFakeTimers(); | ||
render(<OnboardingGuide type='positions_page' />); | ||
|
||
await waitFor(() => jest.advanceTimersByTime(800)); | ||
|
||
expect(screen.queryByText('OnboardingVideo')).not.toBeInTheDocument(); | ||
expect(screen.getByText(positions_modal_text)).toBeInTheDocument(); | ||
expect(screen.getByText('Got it')).toBeInTheDocument(); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
|
||
it('should close the Modal for trading page and start the guide after user clicks on "Let\'s begin" button', async () => { | ||
jest.useFakeTimers(); | ||
render(<OnboardingGuide />); | ||
|
||
await waitFor(() => jest.advanceTimersByTime(800)); | ||
|
||
expect(screen.getByText(trading_modal_text)).toBeInTheDocument(); | ||
expect(screen.queryByText(guide_container)).not.toBeInTheDocument(); | ||
|
||
userEvent.click(screen.getByRole('button')); | ||
await waitFor(() => jest.advanceTimersByTime(300)); | ||
|
||
expect(screen.queryByText(trading_modal_text)).not.toBeInTheDocument(); | ||
expect(screen.getByText(guide_container)).toBeInTheDocument(); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
|
||
it('should close the Modal for positions page, set flag to localStorage equal to true and do NOT start the guide after user clicks on "Got it" button', async () => { | ||
const key = 'guide_dtrader_v2_positions_page'; | ||
jest.useFakeTimers(); | ||
render(<OnboardingGuide type='positions_page' />); | ||
|
||
await waitFor(() => jest.advanceTimersByTime(800)); | ||
|
||
expect(screen.getByText(positions_modal_text)).toBeInTheDocument(); | ||
expect(screen.queryByText(guide_container)).not.toBeInTheDocument(); | ||
expect(localStorage.getItem(key)).toBe('false'); | ||
|
||
userEvent.click(screen.getByRole('button')); | ||
await waitFor(() => jest.advanceTimersByTime(300)); | ||
|
||
expect(screen.queryByText(positions_modal_text)).not.toBeInTheDocument(); | ||
expect(screen.queryByText(guide_container)).not.toBeInTheDocument(); | ||
expect(localStorage.getItem(key)).toBe('true'); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
|
||
it('should close the Modal for trading page and set flag to localStorage equal to true if user clicks on overlay and do NOT start the guide', async () => { | ||
const key = 'guide_dtrader_v2_trade_page'; | ||
jest.useFakeTimers(); | ||
render(<OnboardingGuide />); | ||
|
||
await waitFor(() => jest.advanceTimersByTime(800)); | ||
|
||
expect(screen.getByText(trading_modal_text)).toBeInTheDocument(); | ||
expect(screen.queryByText(guide_container)).not.toBeInTheDocument(); | ||
expect(localStorage.getItem(key)).toBe('false'); | ||
|
||
userEvent.click(screen.getByTestId('dt-actionsheet-overlay')); | ||
await waitFor(() => jest.advanceTimersByTime(300)); | ||
|
||
expect(screen.queryByText(trading_modal_text)).not.toBeInTheDocument(); | ||
expect(screen.queryByText(guide_container)).not.toBeInTheDocument(); | ||
expect(localStorage.getItem(key)).toBe('true'); | ||
|
||
jest.useRealTimers(); | ||
}); | ||
}); |
36 changes: 36 additions & 0 deletions
36
packages/trader/src/AppV2/Components/OnboardingGuide/__tests__/onboarding-video.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React from 'react'; | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import OnboardingVideo from '../onboarding-video'; | ||
|
||
const dt_video = 'dt_onboarding_guide_video'; | ||
const dt_loader = 'square-skeleton'; | ||
|
||
jest.mock('@deriv/shared', () => ({ | ||
...jest.requireActual('@deriv/shared'), | ||
getUrlBase: jest.fn(() => 'video_src.mp4'), | ||
})); | ||
|
||
describe('OnboardingVideo', () => { | ||
beforeAll(() => { | ||
Object.defineProperty(HTMLMediaElement.prototype, 'muted', { | ||
set: jest.fn(), | ||
}); | ||
}); | ||
|
||
it('should render loader and video if the data is not fully loaded', () => { | ||
render(<OnboardingVideo />); | ||
|
||
expect(screen.getByTestId(dt_loader)).toBeInTheDocument(); | ||
expect(screen.getByTestId(dt_video)).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render only video tag if the data has already loaded', () => { | ||
render(<OnboardingVideo />); | ||
|
||
const video = screen.getByTestId(dt_video); | ||
fireEvent.loadedData(video); | ||
|
||
expect(screen.queryByTestId(dt_loader)).not.toBeInTheDocument(); | ||
expect(video).toBeInTheDocument(); | ||
}); | ||
}); |
59 changes: 59 additions & 0 deletions
59
packages/trader/src/AppV2/Components/OnboardingGuide/guide-container.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React from 'react'; | ||
import Joyride, { CallBackProps, STATUS } from 'react-joyride'; | ||
import GuideTooltip from './guide-tooltip'; | ||
import STEPS from './steps-config'; | ||
|
||
type TGuideContainerProps = { | ||
should_run: boolean; | ||
onFinishGuide: () => void; | ||
}; | ||
|
||
type TFinishedStatuses = CallBackProps['status'][]; | ||
|
||
const GuideContainer = ({ should_run, onFinishGuide }: TGuideContainerProps) => { | ||
const [step_index, setStepIndex] = React.useState(0); | ||
|
||
const callbackHandle = (data: CallBackProps) => { | ||
const { status } = data; | ||
const finished_statuses: TFinishedStatuses = [STATUS.FINISHED, STATUS.SKIPPED]; | ||
|
||
if (finished_statuses.includes(status)) onFinishGuide(); | ||
}; | ||
|
||
return ( | ||
<Joyride | ||
continuous | ||
callback={callbackHandle} | ||
disableCloseOnEsc | ||
disableOverlayClose | ||
disableScrolling | ||
floaterProps={{ | ||
styles: { | ||
arrow: { | ||
length: 4, | ||
spread: 8, | ||
display: step_index === 3 ? 'none' : 'inline-flex', | ||
}, | ||
}, | ||
}} | ||
run={should_run} | ||
showSkipButton | ||
steps={STEPS} | ||
spotlightPadding={0} | ||
scrollToFirstStep | ||
styles={{ | ||
options: { | ||
arrowColor: 'var(--component-textIcon-normal-prominent)', | ||
overlayColor: 'var(--core-color-opacity-black-600)', | ||
}, | ||
spotlight: { | ||
borderRadius: 'unset', | ||
}, | ||
}} | ||
stepIndex={step_index} | ||
tooltipComponent={props => <GuideTooltip {...props} setStepIndex={setStepIndex} />} | ||
/> | ||
); | ||
}; | ||
|
||
export default React.memo(GuideContainer); |
Oops, something went wrong.