storybook:(fxa-settings) add signin-confirmed to storybook

Because:

* We're moving the remaining FxA content-server backbone views into
  React, starting with adding them to storybook.

This commit:

* Adds in the signin-confirmed/signin-verified views, and modifies the
  Ready component to accept different values for the header based on
which view is being displayed

Closes #https://mozilla-hub.atlassian.net/browse/FXA-6417
This commit is contained in:
Mill 2022-12-15 16:33:17 -08:00
Родитель 3161a7daf7
Коммит b24688dcbc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 191635F49DE50466
10 изменённых файлов: 294 добавлений и 44 удалений

Просмотреть файл

@ -1 +1 @@
<svg height="2in" width="3in" viewBox="0 0 216 144" xmlns="http://www.w3.org/2000/svg"><style>@keyframes beat{0%,60%,90%,to{transform:scale(1)}25%{transform:scale(.8)}80%{transform:scale(.9)}}.heart{animation:beat 1.5s infinite}</style><radialGradient id="a" cx="85.91" cy="159.8" gradientUnits="userSpaceOnUse" r="102.61"><stop offset=".26" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".4" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".55" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".69" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset=".72" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><radialGradient id="b" cx="72.32" cy="144.71" gradientUnits="userSpaceOnUse" r="150.75"><stop offset=".27" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".46" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".66" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".86" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset=".9" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><radialGradient id="c" cx="129.21" cy="117.26" gradientTransform="matrix(1 0 0 .7 0 35.37)" gradientUnits="userSpaceOnUse" r="112.67"><stop offset=".4" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".58" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".77" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".96" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset="1" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="67.44" x2="126.91" y1="85.38" y2="25.9"><stop offset="0" stop-color="#c689ff"/><stop offset="1" stop-color="#d74cf0"/></linearGradient><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="37.24" x2="138.18" y1="121.61" y2="20.67"><stop offset=".22" stop-color="#b833e1"/><stop offset=".91" stop-color="#ff4f5e"/></linearGradient><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="80.06" x2="199.29" y1="149.59" y2="30.36"><stop offset=".28" stop-color="#7542e5"/><stop offset=".42" stop-color="#824deb"/><stop offset=".79" stop-color="#a067fa"/><stop offset="1" stop-color="#ab71ff"/></linearGradient><path d="M71.24 101.17a9.5 9.5 0 01-9.47 9.5H23.69a7.27 7.27 0 010-14.53 7.17 7.17 0 011.75.22 7.3 7.3 0 01-.2-1.69 7.49 7.49 0 017.5-7.49A7.41 7.41 0 0137 88.49a12.61 12.61 0 0124.8 3.17 9.5 9.5 0 019.44 9.51z" fill="url(#a)"/><path d="M190.14 46.66a10.72 10.72 0 00-2.61.32 11.15 11.15 0 00.29-2.53 11.31 11.31 0 00-17.69-9.32 19 19 0 00-37.37 4.78 14.27 14.27 0 100 28.53h57.39a10.89 10.89 0 100-21.78z" fill="url(#b)"/><path d="M24.87 72.66A22.54 22.54 0 0147.32 50l120.77-.48a22.53 22.53 0 11.18 45.06l-120.77.53a22.54 22.54 0 01-22.63-22.45z" fill="url(#c)"/><path d="M83.89 81.48h29.85v8.65H83.89z" fill="#ff848b"/><path d="M61.36 31.98h71.63v47.31H61.36z" fill="url(#d)"/><path d="M140.78 84.07h-1.95V30.31a3.86 3.86 0 00-3.83-3.86H59.46a3.86 3.86 0 00-3.86 3.87v53.75h-2A1.92 1.92 0 0051.72 86v3.9a1.92 1.92 0 001.93 1.93h87.13a1.93 1.93 0 001.93-1.93V86a1.93 1.93 0 00-1.93-1.93zM105 87.94H89.47v-3.87H105z" fill="url(#e)"/><path class="heart" d="M107.33 47.59a6.26 6.26 0 00-8.85 0l-1.27 1.26L96 47.59a6.26 6.26 0 00-8.85 0 6.26 6.26 0 000 8.85l9 9a1.49 1.49 0 001.07.45 1.51 1.51 0 001.08-.45l9-9a6.26 6.26 0 00.03-8.85z" fill="#f9f9fa" style="transform-origin:45% 38%"/><rect fill="url(#f)" height="62.76" rx="5.4" width="41.61" x="122.66" y="54.8"/><path d="M139.53 107.32h7.75v3.87h-7.75z" fill="#ab71ff"/><path class="heart" d="M153.51 73.93a6.26 6.26 0 00-8.85 0l-1.26 1.26-1.26-1.26a6.26 6.26 0 10-8.85 8.85l9 9a1.53 1.53 0 001.08.45 1.51 1.51 0 001.08-.45l9-9a6.26 6.26 0 00.06-8.85z" fill="#f9f9fa" style="transform-origin:66% 56%"/></svg>
<svg height="2in" width="3in" viewBox="0 0 216 144" xmlns="http://www.w3.org/2000/svg"><style>@keyframes beat{0%,60%,90%,to{transform:scale(1)}25%{transform:scale(.8)}80%{transform:scale(.9)}}.heart{animation:beat 1.5s infinite}</style><radialGradient id="a" cx="85.91" cy="159.8" gradientUnits="userSpaceOnUse" r="102.61"><stop offset=".26" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".4" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".55" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".69" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset=".72" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><radialGradient id="b" cx="72.32" cy="144.71" gradientUnits="userSpaceOnUse" r="150.75"><stop offset=".27" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".46" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".66" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".86" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset=".9" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><radialGradient id="c" cx="129.21" cy="117.26" gradientTransform="matrix(1 0 0 .7 0 35.37)" gradientUnits="userSpaceOnUse" r="112.67"><stop offset=".4" stop-color="#cdcdd4" stop-opacity="0"/><stop offset=".58" stop-color="#cdcdd4" stop-opacity=".02"/><stop offset=".77" stop-color="#cdcdd4" stop-opacity=".08"/><stop offset=".96" stop-color="#cdcdd4" stop-opacity=".18"/><stop offset="1" stop-color="#cdcdd4" stop-opacity=".2"/></radialGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="67.44" x2="126.91" y1="85.38" y2="25.9"><stop offset="0" stop-color="#c689ff"/><stop offset="1" stop-color="#d74cf0"/></linearGradient><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="37.24" x2="138.18" y1="121.61" y2="20.67"><stop offset=".22" stop-color="#b833e1"/><stop offset=".91" stop-color="#ff4f5e"/></linearGradient><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="80.06" x2="199.29" y1="149.59" y2="30.36"><stop offset=".28" stop-color="#7542e5"/><stop offset=".42" stop-color="#824deb"/><stop offset=".79" stop-color="#a067fa"/><stop offset="1" stop-color="#ab71ff"/></linearGradient><path d="M71.24 101.17a9.5 9.5 0 01-9.47 9.5H23.69a7.27 7.27 0 010-14.53 7.17 7.17 0 011.75.22 7.3 7.3 0 01-.2-1.69 7.49 7.49 0 017.5-7.49A7.41 7.41 0 0137 88.49a12.61 12.61 0 0124.8 3.17 9.5 9.5 0 019.44 9.51z" fill="url(#a)"/><path d="M190.14 46.66a10.72 10.72 0 00-2.61.32 11.15 11.15 0 00.29-2.53 11.31 11.31 0 00-17.69-9.32 19 19 0 00-37.37 4.78 14.27 14.27 0 100 28.53h57.39a10.89 10.89 0 100-21.78z" fill="url(#b)"/><path d="M24.87 72.66A22.54 22.54 0 0147.32 50l120.77-.48a22.53 22.53 0 11.18 45.06l-120.77.53a22.54 22.54 0 01-22.63-22.45z" fill="url(#c)"/><path d="M83.89 81.48h29.85v8.65H83.89z" fill="#ff848b"/><path d="M61.36 31.98h71.63v47.31H61.36z" fill="url(#d)"/><path d="M140.78 84.07h-1.95V30.31a3.86 3.86 0 00-3.83-3.86H59.46a3.86 3.86 0 00-3.86 3.87v53.75h-2A1.92 1.92 0 0051.72 86v3.9a1.92 1.92 0 001.93 1.93h87.13a1.93 1.93 0 001.93-1.93V86a1.93 1.93 0 00-1.93-1.93zM105 87.94H89.47v-3.87H105z" fill="url(#e)"/><path class="heart" d="M107.33 47.59a6.26 6.26 0 00-8.85 0l-1.27 1.26L96 47.59a6.26 6.26 0 00-8.85 0 6.26 6.26 0 000 8.85l9 9a1.49 1.49 0 001.07.45 1.51 1.51 0 001.08-.45l9-9a6.26 6.26 0 00.03-8.85z" fill="#f9f9fa" style="transform-origin:45% 38%"/><rect fill="url(#f)" height="62.76" rx="5.4" width="41.61" x="122.66" y="54.8"/><path d="M139.53 107.32h7.75v3.87h-7.75z" fill="#ab71ff"/><path class="heart" d="M153.51 73.93a6.26 6.26 0 00-8.85 0l-1.26 1.26-1.26-1.26a6.26 6.26 0 10-8.85 8.85l9 9a1.53 1.53 0 001.08.45 1.51 1.51 0 001.08-.45l9-9a6.26 6.26 0 00.06-8.85z" fill="#f9f9fa" style="transform-origin:66% 56%"/></svg>

До

Ширина:  |  Высота:  |  Размер: 3.6 KiB

После

Ширина:  |  Высота:  |  Размер: 3.6 KiB

Просмотреть файл

@ -1,8 +1,11 @@
## Ready component
ready-confirmation = Your password has been reset
reset-password-complete-header = Your password has been reset
# This is a string that tells the user they can use whatever service prompted them to reset their password
# Variables:
# $serviceName (String) - the service which caused the user to reset their password
# { $serviceName } represents a product name (e.g., Mozilla VPN) that will be passed in as a variable
ready-use-service = Youre now ready to use { $serviceName }
ready-account-ready = Your account is ready!
ready-continue = Continue
sign-in-complete-header = Sign-in confirmed
pulsing-hearts-description = A pink laptop and a purple mobile device each with a pulsing heart

Просмотреть файл

@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import Ready from '.';
import { ViewNameType } from '.';
import AppLayout from '../../components/AppLayout';
import { Meta } from '@storybook/react';
export default {
title: 'components/Ready',
component: Ready,
} as Meta;
type ReadyWithLayoutPropsType = {
continueHandler?: Function;
isSignedIn?: boolean;
serviceName?: string;
viewName: ViewNameType;
};
const ReadyWithLayout = ({
continueHandler,
isSignedIn,
serviceName,
viewName,
}: ReadyWithLayoutPropsType) => {
return (
<AppLayout>
<Ready {...{ continueHandler, isSignedIn, serviceName, viewName }} />
</AppLayout>
);
};
export const SigninConfirmedOrSigninVerified = () => (
<ReadyWithLayout viewName="signin-confirmed" />
);
export const ResetPasswordConfirmForLoggedOutUser = () => (
<ReadyWithLayout isSignedIn={false} viewName="reset-password-confirmed" />
);
export const ResetPasswordConfirmedWithRelyingParty = () => (
<ReadyWithLayout
serviceName="Example Service"
viewName="reset-password-confirmed"
/>
);
export const WithRelyingPartyNoContinueAction = () => (
<ReadyWithLayout serviceName="Example Service" viewName="signin-confirmed" />
);
export const WithRelyingPartyAndContinueAction = () => (
<ReadyWithLayout
serviceName={'Example Service'}
viewName="reset-password-confirmed"
continueHandler={() => {
console.log('Arbitrary action');
}}
/>
);

Просмотреть файл

@ -4,6 +4,8 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { getFtlBundle, testL10n } from 'fxa-react/lib/test-utils';
import { FluentBundle } from '@fluent/bundle';
import Ready from '.';
import { logViewEvent, usePageViewEvent } from '../../lib/metrics';
@ -14,10 +16,18 @@ jest.mock('../../lib/metrics', () => ({
describe('Ready', () => {
const customServiceName = 'Example Service';
const viewName = 'example-view';
const viewName = 'reset-password-confirmed';
let bundle: FluentBundle;
beforeAll(async () => {
bundle = await getFtlBundle('settings');
});
it('renders as expected with default values', () => {
render(<Ready viewName={viewName} />);
render(<Ready {...{ viewName }} />);
const ftlMsgMock = screen.getAllByTestId('ftlmsg-mock')[1];
testL10n(ftlMsgMock, bundle, {
serviceName: 'Account Settings',
});
const passwordResetConfirmation = screen.getByText(
'Your password has been reset'
@ -33,9 +43,8 @@ describe('Ready', () => {
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});
// it renders as expected with a custom service name.
it('renders as expected when given a service name', () => {
render(<Ready viewName={viewName} serviceName={customServiceName} />);
render(<Ready {...{ viewName }} serviceName={customServiceName} />);
const passwordResetConfirmation = screen.getByText(
'Your password has been reset'
@ -51,10 +60,25 @@ describe('Ready', () => {
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});
it('renders as expected when page is viewed by a logged out user', () => {
render(<Ready isSignedIn={false} {...{ viewName }} />);
const passwordResetConfirmation = screen.getByText(
'Your password has been reset'
);
const serviceAvailabilityConfirmation = screen.getByText(
'Your account is ready!'
);
expect(passwordResetConfirmation).toBeInTheDocument();
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});
it('renders as expected when given a service name and relier continue action', () => {
render(
<Ready
viewName={viewName}
{...{
viewName,
}}
serviceName={customServiceName}
continueHandler={() => {
console.log('beepboop');
@ -76,21 +100,21 @@ describe('Ready', () => {
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});
it('emits a metrics event on render', async () => {
it('emits a metrics event on render', () => {
render(<Ready viewName={viewName} />);
expect(usePageViewEvent).toHaveBeenCalledWith(viewName, {
entrypoint_variation: 'react',
});
});
it('emits a metrics event when a user clicks `Continue`', async () => {
it('emits a metrics event when a user clicks `Continue`', () => {
render(
<Ready
viewName={viewName}
serviceName={customServiceName}
continueHandler={() => {
console.log('beepboop');
}}
serviceName={customServiceName}
{...{ viewName }}
/>
);
const passwordResetContinueButton = screen.getByText('Continue');

Просмотреть файл

@ -4,58 +4,107 @@
import React from 'react';
import { RouteComponentProps } from '@reach/router';
import { Localized } from '@fluent/react';
import { FtlMsg } from 'fxa-react/lib/utils';
import { ReactComponent as PulseHearts } from './account-verified.svg';
import { logViewEvent, usePageViewEvent } from '../../lib/metrics';
import { useFtlMsgResolver } from '../../models/hooks';
// We'll actually be getting the isSignedIn value from a context when this is wired up.
type ReadyProps = {
serviceName?: string;
continueHandler?: Function;
viewName: string;
isSignedIn?: boolean;
serviceName?: string;
viewName: ViewNameType;
};
export type ViewNameType =
| 'signin-confirmed'
| 'signin-verified'
| 'reset-password-confirmed'
| 'reset-password-verified'
| 'reset-password-with-recovery-key-verified';
const getTemplateValues = (viewName: ViewNameType) => {
let templateValues = {
headerText: '',
headerId: '',
};
switch (viewName) {
case 'signin-confirmed':
case 'signin-verified':
templateValues.headerId = 'sign-in-complete-header';
templateValues.headerText = 'Sign-in confirmed';
break;
case 'reset-password-confirmed':
case 'reset-password-with-recovery-key-verified':
templateValues.headerId = 'reset-password-complete-header';
templateValues.headerText = 'Your password has been reset';
break;
default:
throw new Error('Invalid view name submitted to Ready component');
}
return templateValues;
};
const Ready = ({
serviceName = 'Account Settings',
continueHandler,
isSignedIn = true,
serviceName = 'Account Settings',
viewName,
}: ReadyProps & RouteComponentProps) => {
usePageViewEvent(viewName, {
entrypoint_variation: 'react',
});
const templateValues = getTemplateValues(viewName);
const ftlMsgResolver = useFtlMsgResolver();
const pulsingHeartsAltText = ftlMsgResolver.getMsg(
'pulsing-hearts-description',
'A pink laptop and a purple mobile device each with a pulsing heart'
);
return (
<>
<div className="mb-4">
<Localized id="ready-confirmation">
<h1 className="card-header">Your password has been reset</h1>
</Localized>
<h1 className="card-header">
<FtlMsg id={templateValues.headerId}>
{templateValues.headerText}
</FtlMsg>
</h1>
</div>
<div className="flex justify-center mx-auto">
<PulseHearts />
<PulseHearts
className="w-3/5"
role="img"
aria-label={pulsingHeartsAltText}
/>
</div>
<section>
<div className="error"></div>
<Localized id="ready-use-service">
<p className="my-4 text-sm">{`Youre now ready to use ${serviceName}`}</p>
</Localized>
{isSignedIn ? (
<FtlMsg id="ready-use-service" vars={{ serviceName }}>
<p className="my-4 text-sm">{`Youre now ready to use ${serviceName}`}</p>
</FtlMsg>
) : (
<FtlMsg id="ready-account-ready">
<p className="my-4 text-sm">Your account is ready!</p>
</FtlMsg>
)}
</section>
{continueHandler && (
<div className="flex justify-center mx-auto mt-6 max-w-64">
<Localized id="ready-continue">
<button
type="submit"
className="cta-primary cta-base-p font-bold mx-2 flex-1"
onClick={(e) => {
const eventName = `${viewName}.continue`;
logViewEvent(viewName, eventName, {
entrypoint_variation: 'react',
});
continueHandler(e);
}}
>
Continue
</button>
</Localized>
<button
type="submit"
className="cta-primary cta-base-p font-bold mx-2 flex-1"
onClick={(e) => {
const eventName = `${viewName}.continue`;
logViewEvent(viewName, eventName, {
entrypoint_variation: 'react',
});
continueHandler(e);
}}
>
<FtlMsg id="ready-continue">Continue</FtlMsg>
</button>
</div>
)}
</>

Просмотреть файл

@ -15,16 +15,12 @@ jest.mock('../../lib/metrics', () => ({
describe('ResetPasswordConfirmed', () => {
it('renders Ready component as expected', () => {
render(<ResetPasswordConfirmed />);
// Calling `getByText` will fail if these elements aren't in the document,
// but we test anyway to make the intention of the test explicit
const passwordResetConfirmation = screen.getByText(
'Your password has been reset'
);
const serviceAvailabilityConfirmation = screen.getByText(
'Youre now ready to use Account Settings'
);
const passwordResetContinueButton = screen.queryByText('Continue');
expect(passwordResetContinueButton).not.toBeInTheDocument();
expect(passwordResetConfirmation).toBeInTheDocument();
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});

Просмотреть файл

@ -5,7 +5,7 @@
import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderWithRouter } from '../../models/mocks';
import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils';
import { getFtlBundle, testL10n } from 'fxa-react/lib/test-utils';
import { FluentBundle } from '@fluent/bundle';
import ResetPasswordWithRecoveryKeyVerified from '.';
import { logViewEvent } from '../../lib/metrics';
@ -22,7 +22,10 @@ describe('ResetPasswordWithRecoveryKeyVerified', () => {
});
it('renders default content as expected', () => {
renderWithRouter(<ResetPasswordWithRecoveryKeyVerified />);
testAllL10n(screen, bundle);
const ftlMsgMock = screen.getAllByTestId('ftlmsg-mock')[1];
testL10n(ftlMsgMock, bundle, {
serviceName: 'Account Settings',
});
const newAccountRecoveryKeyButton = screen.getByText(
'Generate a new account recovery key'

Просмотреть файл

@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import SigninConfirmed from '.';
import AppLayout from '../../components/AppLayout';
import { LocationProvider } from '@reach/router';
import { Meta } from '@storybook/react';
export default {
title: 'pages/SigninConfirmed',
component: SigninConfirmed,
} as Meta;
export const Default = () => (
<LocationProvider>
<AppLayout>
<SigninConfirmed />
</AppLayout>
</LocationProvider>
);

Просмотреть файл

@ -0,0 +1,67 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { getFtlBundle, testL10n } from 'fxa-react/lib/test-utils';
import { FluentBundle } from '@fluent/bundle';
import SigninConfirmed from '.';
import { logViewEvent, usePageViewEvent } from '../../lib/metrics';
jest.mock('../../lib/metrics', () => ({
logViewEvent: jest.fn(),
usePageViewEvent: jest.fn(),
}));
describe('SigninConfirmed', () => {
let bundle: FluentBundle;
beforeAll(async () => {
bundle = await getFtlBundle('settings');
});
it('renders Ready component as expected', () => {
render(<SigninConfirmed />);
const ftlMsgMock = screen.getAllByTestId('ftlmsg-mock')[1];
testL10n(ftlMsgMock, bundle, {
serviceName: 'Account Settings',
});
const signinConfirmation = screen.getByText('Sign-in confirmed');
const serviceAvailabilityConfirmation = screen.getByText(
'Youre now ready to use Account Settings'
);
const signinContinueButton = screen.queryByText('Continue');
// Calling `getByText` will fail if these elements aren't in the document,
// but we test anyway to make the intention of the test explicit
expect(signinContinueButton).not.toBeInTheDocument();
expect(signinConfirmation).toBeInTheDocument();
expect(serviceAvailabilityConfirmation).toBeInTheDocument();
});
it('emits the expected metrics on render', () => {
render(<SigninConfirmed />);
expect(usePageViewEvent).toHaveBeenCalledWith('signin-confirmed', {
entrypoint_variation: 'react',
});
});
it('emits the expected metrics when a user clicks `Continue`', () => {
render(
<SigninConfirmed
continueHandler={() => {
console.log('beepboop');
}}
/>
);
const passwordResetContinueButton = screen.getByText('Continue');
fireEvent.click(passwordResetContinueButton);
expect(logViewEvent).toHaveBeenCalledWith(
'signin-confirmed',
'signin-confirmed.continue',
{
entrypoint_variation: 'react',
}
);
});
});

Просмотреть файл

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import { RouteComponentProps } from '@reach/router';
import Ready from '../../components/Ready';
type SigninConfirmedProps = {
continueHandler?: Function;
serviceName?: string;
};
const SigninConfirmed = ({
continueHandler,
serviceName,
}: SigninConfirmedProps & RouteComponentProps) => {
const viewName = 'signin-confirmed';
return <Ready {...{ continueHandler, viewName, serviceName }} />;
};
export default SigninConfirmed;