mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #18102 from MetaMask/fix/599-fix-theme-issues-of-desktop-pairing-page-in-the-extension-ui
fix: fix theme issues of desktop pairing page
This commit is contained in:
commit
f32d71ba1a
@ -121,12 +121,17 @@ export async function getErrorHtml(
|
|||||||
}
|
}
|
||||||
|
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||||
|
export const MMD_DOWNLOAD_LINK =
|
||||||
|
'https://github.com/MetaMask/metamask-desktop/releases';
|
||||||
|
|
||||||
function disableDesktop(backgroundConnection) {
|
function disableDesktop(backgroundConnection) {
|
||||||
backgroundConnection.disableDesktopError();
|
backgroundConnection.disableDesktopError();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadDesktopApp() {
|
export function downloadDesktopApp() {
|
||||||
global.platform.openTab({ url: 'https://metamask.io/' });
|
global.platform.openTab({
|
||||||
|
url: MMD_DOWNLOAD_LINK,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadExtension() {
|
export function downloadExtension() {
|
||||||
@ -139,7 +144,7 @@ export function restartExtension() {
|
|||||||
|
|
||||||
export function openOrDownloadMMD() {
|
export function openOrDownloadMMD() {
|
||||||
openCustomProtocol('metamask-desktop://pair').catch(() => {
|
openCustomProtocol('metamask-desktop://pair').catch(() => {
|
||||||
window.open('https://metamask.io/download.html', '_blank').focus();
|
window.open(MMD_DOWNLOAD_LINK, '_blank').focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,48 @@
|
|||||||
|
import browser from 'webextension-polyfill';
|
||||||
import { fetchLocale } from '../../ui/helpers/utils/i18n-helper';
|
import { fetchLocale } from '../../ui/helpers/utils/i18n-helper';
|
||||||
import { SUPPORT_LINK } from './ui-utils';
|
import { SUPPORT_LINK } from './ui-utils';
|
||||||
import { getErrorHtml } from './error-utils';
|
import {
|
||||||
|
downloadDesktopApp,
|
||||||
|
openOrDownloadMMD,
|
||||||
|
downloadExtension,
|
||||||
|
getErrorHtml,
|
||||||
|
restartExtension,
|
||||||
|
registerDesktopErrorActions,
|
||||||
|
MMD_DOWNLOAD_LINK,
|
||||||
|
} from './error-utils';
|
||||||
|
import { openCustomProtocol } from './deep-linking';
|
||||||
|
|
||||||
jest.mock('../../ui/helpers/utils/i18n-helper', () => ({
|
jest.mock('../../ui/helpers/utils/i18n-helper', () => ({
|
||||||
fetchLocale: jest.fn(),
|
fetchLocale: jest.fn(),
|
||||||
loadRelativeTimeFormatLocaleData: jest.fn(),
|
loadRelativeTimeFormatLocaleData: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
jest.mock('./deep-linking', () => ({
|
||||||
|
openCustomProtocol: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('webextension-polyfill', () => {
|
||||||
|
return {
|
||||||
|
runtime: {
|
||||||
|
reload: jest.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe('Error utils Tests', function () {
|
describe('Error utils Tests', function () {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
|
||||||
|
global.platform = {
|
||||||
|
openTab: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
delete global.platform;
|
||||||
|
});
|
||||||
it('should get error html', async function () {
|
it('should get error html', async function () {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
localeMessages: {
|
localeMessages: {
|
||||||
@ -50,4 +85,93 @@ describe('Error utils Tests', function () {
|
|||||||
expect(errorHtml).toContain(stillGettingMessageMessage);
|
expect(errorHtml).toContain(stillGettingMessageMessage);
|
||||||
expect(errorHtml).toContain(sendBugReportMessage);
|
expect(errorHtml).toContain(sendBugReportMessage);
|
||||||
});
|
});
|
||||||
|
describe('desktop', () => {
|
||||||
|
it('downloadDesktopApp opens a new tab on metamask-desktop releases url', () => {
|
||||||
|
downloadDesktopApp();
|
||||||
|
|
||||||
|
expect(global.platform.openTab).toHaveBeenCalledTimes(1);
|
||||||
|
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||||
|
url: MMD_DOWNLOAD_LINK,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('downloadExtension opens a new tab on metamask extension url', () => {
|
||||||
|
downloadExtension();
|
||||||
|
|
||||||
|
expect(global.platform.openTab).toHaveBeenCalledTimes(1);
|
||||||
|
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||||
|
url: 'https://metamask.io/',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('restartExtension calls runtime reload method', () => {
|
||||||
|
restartExtension();
|
||||||
|
|
||||||
|
expect(browser.runtime.reload).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('openOrDownloadMMD', () => {
|
||||||
|
it('launches installed desktop app by calling openCustomProtocol successfully', () => {
|
||||||
|
openCustomProtocol.mockResolvedValue();
|
||||||
|
openOrDownloadMMD();
|
||||||
|
|
||||||
|
expect(openCustomProtocol).toHaveBeenCalledTimes(1);
|
||||||
|
expect(openCustomProtocol).toHaveBeenCalledWith(
|
||||||
|
'metamask-desktop://pair',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens metamask-desktop release url when fails to find and start a local metamask-desktop app', async () => {
|
||||||
|
openCustomProtocol.mockRejectedValue();
|
||||||
|
const focusMock = jest.fn();
|
||||||
|
jest.spyOn(window, 'open').mockReturnValue({
|
||||||
|
focus: focusMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
openOrDownloadMMD();
|
||||||
|
|
||||||
|
// this ensures that we are awaiting for pending promises to resolve
|
||||||
|
// as the openOrDownloadMMD calls a promise, but returns before it is resolved
|
||||||
|
await new Promise(process.nextTick);
|
||||||
|
|
||||||
|
expect(openCustomProtocol).toHaveBeenCalledTimes(1);
|
||||||
|
expect(openCustomProtocol).toHaveBeenCalledWith(
|
||||||
|
'metamask-desktop://pair',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(window.open).toHaveBeenCalledTimes(1);
|
||||||
|
expect(window.open).toHaveBeenCalledWith(MMD_DOWNLOAD_LINK, '_blank');
|
||||||
|
expect(focusMock).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('registerDesktopErrorActions add click event listeners for each desktop error elements', async () => {
|
||||||
|
const addEventListenerMock = jest.fn();
|
||||||
|
jest.spyOn(document, 'getElementById').mockReturnValue({
|
||||||
|
addEventListener: addEventListenerMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
registerDesktopErrorActions();
|
||||||
|
|
||||||
|
expect(document.getElementById).toHaveBeenCalledTimes(4);
|
||||||
|
expect(document.getElementById).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'desktop-error-button-disable-mmd',
|
||||||
|
);
|
||||||
|
expect(document.getElementById).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'desktop-error-button-restart-mm',
|
||||||
|
);
|
||||||
|
expect(document.getElementById).toHaveBeenNthCalledWith(
|
||||||
|
3,
|
||||||
|
'desktop-error-button-download-mmd',
|
||||||
|
);
|
||||||
|
expect(document.getElementById).toHaveBeenNthCalledWith(
|
||||||
|
4,
|
||||||
|
'desktop-error-button-open-or-download-mmd',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(addEventListenerMock).toHaveBeenCalledTimes(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,16 +3,13 @@
|
|||||||
exports[`Desktop Pairing page should render otp component 1`] = `
|
exports[`Desktop Pairing page should render otp component 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="page-container__content"
|
class="box box--margin-right-2 box--margin-left-2 box--display-flex box--flex-direction-column box--align-items-center"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="desktop-pairing"
|
class="box box--margin-top-8 box--margin-bottom-8 box--display-flex box--flex-direction-row box--justify-content-center"
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="box box--margin-top-12 box--margin-right-6 box--margin-left-6 box--display-flex box--flex-direction-column box--align-items-center box--text-align-center"
|
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
class="desktop-pairing__icon"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
height="64"
|
height="64"
|
||||||
viewBox="0 0 64 39"
|
viewBox="0 0 64 39"
|
||||||
@ -93,27 +90,21 @@ exports[`Desktop Pairing page should render otp component 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h3
|
||||||
<div
|
align="center"
|
||||||
class="desktop-pairing__title"
|
class="box mm-text mm-text--heading-md box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Pair with Desktop
|
Pair with Desktop
|
||||||
</div>
|
</h3>
|
||||||
<div
|
<p
|
||||||
class="desktop-pairing__subtitle"
|
align="center"
|
||||||
|
class="box mm-text mm-text--body-md box--margin-top-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Open your MetaMask Desktop and type this code
|
Open your MetaMask Desktop and type this code
|
||||||
</div>
|
</p>
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="desktop-pairing"
|
class="box desktop-pairing__clickable box--margin-top-6 box--margin-bottom-6 box--flex-direction-row"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="desktop-pairing__clickable"
|
|
||||||
data-testid="desktop-pairing-otp-content"
|
data-testid="desktop-pairing-otp-content"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="box box--margin-right-6 box--margin-left-6 box--display-flex box--flex-direction-column box--align-items-center box--text-align-center"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="desktop-pairing__tooltip-wrapper"
|
class="desktop-pairing__tooltip-wrapper"
|
||||||
@ -126,16 +117,20 @@ exports[`Desktop Pairing page should render otp component 1`] = `
|
|||||||
style="display: inline;"
|
style="display: inline;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<p
|
<h1
|
||||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography desktop-pairing__otp typography--p typography--weight-normal typography--style-normal typography--align-center typography--color-text-default"
|
align="center"
|
||||||
|
class="box mm-text desktop-pairing__otp mm-text--display-md box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
123456
|
123456
|
||||||
</p>
|
</h1>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="box box--margin-top-4 box--margin-bottom-6 box--display-flex box--flex-direction-row box--justify-content-center box--align-items-center"
|
||||||
|
>
|
||||||
<p
|
<p
|
||||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography desktop-pairing__countdown-timer typography--p typography--weight-normal typography--style-normal typography--align-center typography--color-text-default"
|
align="center"
|
||||||
|
class="box mm-text desktop-pairing__countdown-timer mm-text--body-md box--padding-2 box--flex-direction-row box--color-text-default box--background-color-background-default box--rounded-xl"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
|
|
||||||
@ -149,20 +144,19 @@ exports[`Desktop Pairing page should render otp component 1`] = `
|
|||||||
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<div
|
</div>
|
||||||
class="desktop-pairing__description"
|
<p
|
||||||
|
align="center"
|
||||||
|
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
If the pairing is successful, extension will restart and you'll have to re-enter your password.
|
If the pairing is successful, extension will restart and you'll have to re-enter your password.
|
||||||
</div>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="desktop-pairing__buttons"
|
class="box box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button btn--rounded btn-primary"
|
class="box mm-text mm-button-base mm-button-base--size-md mm-button-primary mm-text--body-md box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-inverse box--background-color-primary-default box--rounded-pill"
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
Done
|
Done
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
import React, { useState, useEffect, useRef, useContext } from 'react';
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Button from '../../components/ui/button';
|
|
||||||
import { SECOND } from '../../../shared/constants/time';
|
import { SECOND } from '../../../shared/constants/time';
|
||||||
import Typography from '../../components/ui/typography';
|
|
||||||
import { I18nContext } from '../../contexts/i18n';
|
import { I18nContext } from '../../contexts/i18n';
|
||||||
import IconDesktopPairing from '../../components/ui/icon/icon-desktop-pairing';
|
import IconDesktopPairing from '../../components/ui/icon/icon-desktop-pairing';
|
||||||
import {
|
import {
|
||||||
TEXT_ALIGN,
|
TEXT_ALIGN,
|
||||||
TypographyVariant,
|
TextVariant,
|
||||||
DISPLAY,
|
DISPLAY,
|
||||||
AlignItems,
|
AlignItems,
|
||||||
FLEX_DIRECTION,
|
JustifyContent,
|
||||||
|
BackgroundColor,
|
||||||
|
BorderRadius,
|
||||||
} from '../../helpers/constants/design-system';
|
} from '../../helpers/constants/design-system';
|
||||||
import Box from '../../components/ui/box/box';
|
import Box from '../../components/ui/box/box';
|
||||||
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||||
import Tooltip from '../../components/ui/tooltip';
|
import Tooltip from '../../components/ui/tooltip';
|
||||||
|
import { Text, Button } from '../../components/component-library';
|
||||||
|
|
||||||
export default function DesktopPairingPage({
|
export default function DesktopPairingPage({
|
||||||
generateDesktopOtp,
|
generateDesktopOtp,
|
||||||
@ -75,19 +76,14 @@ export default function DesktopPairingPage({
|
|||||||
|
|
||||||
const renderIcon = () => {
|
const renderIcon = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<Box
|
<Box
|
||||||
display={DISPLAY.FLEX}
|
display={DISPLAY.FLEX}
|
||||||
alignItems={AlignItems.center}
|
justifyContent={JustifyContent.center}
|
||||||
textAlign={TEXT_ALIGN.CENTER}
|
marginTop={8}
|
||||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
marginBottom={8}
|
||||||
marginLeft={6}
|
|
||||||
marginRight={6}
|
|
||||||
marginTop={12}
|
|
||||||
>
|
>
|
||||||
<IconDesktopPairing size={64} />
|
<IconDesktopPairing className="desktop-pairing__icon" size={64} />
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,81 +100,94 @@ export default function DesktopPairingPage({
|
|||||||
hideLoadingIndication();
|
hideLoadingIndication();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
|
<Text variant={TextVariant.headingMd} align={TEXT_ALIGN.CENTER}>
|
||||||
|
{t('desktopPageTitle')}
|
||||||
|
</Text>
|
||||||
|
<Text marginTop={2} align={TEXT_ALIGN.CENTER}>
|
||||||
|
{t('desktopPageSubTitle')}
|
||||||
|
</Text>
|
||||||
|
<Box
|
||||||
|
marginBottom={6}
|
||||||
|
marginTop={6}
|
||||||
className="desktop-pairing__clickable"
|
className="desktop-pairing__clickable"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleCopy(otp);
|
handleCopy(otp);
|
||||||
}}
|
}}
|
||||||
data-testid="desktop-pairing-otp-content"
|
data-testid="desktop-pairing-otp-content"
|
||||||
>
|
|
||||||
<Box
|
|
||||||
display={DISPLAY.FLEX}
|
|
||||||
alignItems={AlignItems.center}
|
|
||||||
textAlign={TEXT_ALIGN.CENTER}
|
|
||||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
|
||||||
marginLeft={6}
|
|
||||||
marginRight={6}
|
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
wrapperClassName="desktop-pairing__tooltip-wrapper"
|
wrapperClassName="desktop-pairing__tooltip-wrapper"
|
||||||
position="top"
|
position="top"
|
||||||
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
|
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
|
||||||
>
|
>
|
||||||
<Typography
|
<Text
|
||||||
align={TEXT_ALIGN.CENTER}
|
align={TEXT_ALIGN.CENTER}
|
||||||
|
variant={TextVariant.displayMd}
|
||||||
className="desktop-pairing__otp"
|
className="desktop-pairing__otp"
|
||||||
>
|
>
|
||||||
{otp}
|
{otp}
|
||||||
</Typography>
|
</Text>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
<Typography
|
alignItems={AlignItems.center}
|
||||||
variant={TypographyVariant.paragraph}
|
justifyContent={JustifyContent.center}
|
||||||
align={TEXT_ALIGN.CENTER}
|
marginTop={4}
|
||||||
|
marginBottom={6}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
className="desktop-pairing__countdown-timer"
|
className="desktop-pairing__countdown-timer"
|
||||||
|
variant={TextVariant.paragraph}
|
||||||
|
align={TEXT_ALIGN.CENTER}
|
||||||
|
backgroundColor={BackgroundColor.backgroundDefault}
|
||||||
|
borderRadius={BorderRadius.XL}
|
||||||
|
padding={2}
|
||||||
>
|
>
|
||||||
{t('desktopPairingExpireMessage', [
|
{t('desktopPairingExpireMessage', [
|
||||||
<span className="desktop-pairing__countdown-timer-seconds" key={1}>
|
<span
|
||||||
|
className="desktop-pairing__countdown-timer-seconds"
|
||||||
|
key={1}
|
||||||
|
>
|
||||||
{getExpireDuration()}
|
{getExpireDuration()}
|
||||||
</span>,
|
</span>,
|
||||||
])}
|
])}
|
||||||
</Typography>
|
</Text>
|
||||||
<div className="desktop-pairing__description">
|
</Box>
|
||||||
|
<Text align={TEXT_ALIGN.CENTER} variant={TextVariant.bodySm}>
|
||||||
{t('desktopPageDescription')}
|
{t('desktopPageDescription')}
|
||||||
</div>
|
</Text>
|
||||||
</div>
|
</Box>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderFooter = () => {
|
const renderFooter = () => {
|
||||||
return (
|
return (
|
||||||
<div className="desktop-pairing__buttons">
|
<Box>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
|
||||||
rounded
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
goBack();
|
goBack();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('done')}
|
{t('done')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-container__content">
|
<Box
|
||||||
<div className="desktop-pairing">
|
display={DISPLAY.FLEX}
|
||||||
|
flexDirection="column"
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
marginLeft={2}
|
||||||
|
marginRight={2}
|
||||||
|
>
|
||||||
{renderIcon()}
|
{renderIcon()}
|
||||||
<div className="desktop-pairing__title">{t('desktopPageTitle')}</div>
|
{renderContent()}
|
||||||
<div className="desktop-pairing__subtitle">
|
|
||||||
{t('desktopPageSubTitle')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="desktop-pairing">{renderContent()}</div>
|
|
||||||
{renderFooter()}
|
{renderFooter()}
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
ui/pages/desktop-pairing/desktop-pairing.stories.js
Normal file
30
ui/pages/desktop-pairing/desktop-pairing.stories.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import DesktopPairingPage from './desktop-pairing.component';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/DesktopPairingPage',
|
||||||
|
component: DesktopPairingPage,
|
||||||
|
argTypes: {
|
||||||
|
showLoadingIndication: {
|
||||||
|
action: 'showLoadingIndication',
|
||||||
|
},
|
||||||
|
hideLoadingIndication: {
|
||||||
|
action: 'hideLoadingIndication',
|
||||||
|
},
|
||||||
|
generateDesktopOtp: {
|
||||||
|
action: 'generateDesktopOtp',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
mostRecentOverviewPage: '/',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultStory = (args) => {
|
||||||
|
const generateDesktopOtp = async () => Promise.resolve('123456');
|
||||||
|
return (
|
||||||
|
<DesktopPairingPage {...args} generateDesktopOtp={generateDesktopOtp} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultStory.storyName = 'Default';
|
@ -1,11 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import reactRouterDom from 'react-router-dom';
|
import reactRouterDom from 'react-router-dom';
|
||||||
import { waitFor, act, screen } from '@testing-library/react';
|
import { waitFor, act, screen, fireEvent } from '@testing-library/react';
|
||||||
import actions from '../../store/actions';
|
import actions from '../../store/actions';
|
||||||
import configureStore from '../../store/store';
|
import configureStore from '../../store/store';
|
||||||
import { renderWithProvider } from '../../../test/jest';
|
import { renderWithProvider } from '../../../test/jest';
|
||||||
import mockState from '../../../test/data/mock-state.json';
|
import mockState from '../../../test/data/mock-state.json';
|
||||||
import { SECOND } from '../../../shared/constants/time';
|
import { SECOND } from '../../../shared/constants/time';
|
||||||
|
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||||
import DesktopPairingPage from '.';
|
import DesktopPairingPage from '.';
|
||||||
|
|
||||||
const mockHideLoadingIndication = jest.fn();
|
const mockHideLoadingIndication = jest.fn();
|
||||||
@ -19,10 +20,13 @@ jest.mock('../../store/actions', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../../hooks/useCopyToClipboard');
|
||||||
|
|
||||||
const mockedActions = actions;
|
const mockedActions = actions;
|
||||||
|
|
||||||
describe('Desktop Pairing page', () => {
|
describe('Desktop Pairing page', () => {
|
||||||
const mockHistoryPush = jest.fn();
|
const mockHistoryPush = jest.fn();
|
||||||
|
const handleCopy = jest.fn();
|
||||||
|
|
||||||
function flushPromises() {
|
function flushPromises() {
|
||||||
// Wait for promises running in the non-async timer callback to complete.
|
// Wait for promises running in the non-async timer callback to complete.
|
||||||
@ -35,6 +39,7 @@ describe('Desktop Pairing page', () => {
|
|||||||
.spyOn(reactRouterDom, 'useHistory')
|
.spyOn(reactRouterDom, 'useHistory')
|
||||||
.mockImplementation()
|
.mockImplementation()
|
||||||
.mockReturnValue({ push: mockHistoryPush });
|
.mockReturnValue({ push: mockHistoryPush });
|
||||||
|
useCopyToClipboard.mockReturnValue([false, handleCopy]);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -107,4 +112,53 @@ describe('Desktop Pairing page', () => {
|
|||||||
jest.clearAllTimers();
|
jest.clearAllTimers();
|
||||||
jest.useRealTimers();
|
jest.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should copy otp value when content is clicked', async () => {
|
||||||
|
const otp = '123456';
|
||||||
|
mockedActions.generateDesktopOtp.mockResolvedValue(otp);
|
||||||
|
|
||||||
|
const store = configureStore(mockState);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
renderWithProvider(<DesktopPairingPage />, store);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('desktop-pairing-otp-content')).toBeDefined();
|
||||||
|
expect(screen.getByText(otp)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(screen.getByTestId('desktop-pairing-otp-content'));
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(handleCopy).toHaveBeenCalledWith(otp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return to previews page when the done button is clicked', async () => {
|
||||||
|
const otp = '123456';
|
||||||
|
const mostRecentOverviewPage = '/mostRecentOverviewPage';
|
||||||
|
mockedActions.generateDesktopOtp.mockResolvedValue(otp);
|
||||||
|
|
||||||
|
const store = configureStore(mockState);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
renderWithProvider(<DesktopPairingPage />, store);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('desktop-pairing-otp-content')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(screen.getByText('Done'));
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockHistoryPush).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockHistoryPush).toHaveBeenCalledWith(mostRecentOverviewPage);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,128 +1,28 @@
|
|||||||
.desktop-pairing {
|
.desktop-pairing {
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 30px 0;
|
|
||||||
|
|
||||||
&__countdown-timer {
|
&__countdown-timer {
|
||||||
background: #f2f3f4;
|
|
||||||
border-radius: 15.5px;
|
|
||||||
padding: 7px 0 7px 0;
|
|
||||||
margin: 0 32px 0 32px;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__countdown-timer-seconds {
|
&__countdown-timer-seconds {
|
||||||
color: var(--color-primary-default);
|
color: var(--color-primary-default);
|
||||||
}
|
min-width: 180px;
|
||||||
|
|
||||||
&__icon {
|
|
||||||
padding-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 140.62%;
|
|
||||||
text-align: center;
|
|
||||||
color: #24292e;
|
|
||||||
padding-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__subtitle,
|
|
||||||
&__description {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 140.62%;
|
|
||||||
text-align: center;
|
|
||||||
color: #000;
|
|
||||||
padding-top: 8px;
|
|
||||||
margin: 0 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__description {
|
|
||||||
margin: 18px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__otp {
|
&__otp {
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 48px;
|
|
||||||
letter-spacing: 10px;
|
letter-spacing: 10px;
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
display: flex;
|
|
||||||
width: 70%;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tooltip-wrapper {
|
&__tooltip-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__clickable {
|
&__clickable:hover {
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.desktop-pairing-warning {
|
&__icon {
|
||||||
font-style: normal;
|
path {
|
||||||
font-weight: 400;
|
fill: var(--color-icon-default);
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
&__close-button {
|
|
||||||
z-index: 1050;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&__close::after {
|
|
||||||
content: '\00D7';
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
float: right;
|
|
||||||
margin-top: -8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
color: var(--color-primary-default);
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 100%;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
padding: 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__warning-content {
|
|
||||||
border-left: 5px solid var(--color-warning-default);
|
|
||||||
border-right: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
border-top: 0;
|
|
||||||
margin: 4px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
|
||||||
top: 10px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user