зеркало из https://github.com/mozilla/fxa.git
Merge pull request #17034 from mozilla/FXA-9529
feat(glean): Add front-end glean events for reset pwd with code
This commit is contained in:
Коммит
1e25c59475
|
@ -3,14 +3,24 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import LinkRememberPassword from '.';
|
||||
import LinkRememberPassword, { LinkRememberPasswordProps } from '.';
|
||||
import { MOCK_ACCOUNT } from '../../models/mocks';
|
||||
import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils';
|
||||
import { FluentBundle } from '@fluent/bundle';
|
||||
import { MOCK_CLIENT_ID, MOCK_EMAIL } from '../../pages/mocks';
|
||||
import { LocationProvider } from '@reach/router';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
jest.mock('../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
passwordReset: {
|
||||
emailConfirmationSignin: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const mockLocation = () => {
|
||||
return {
|
||||
|
@ -23,9 +33,12 @@ jest.mock('@reach/router', () => ({
|
|||
useLocation: () => mockLocation(),
|
||||
}));
|
||||
|
||||
const Subject = ({ email = MOCK_ACCOUNT.primaryEmail.email }) => (
|
||||
const Subject = ({
|
||||
email = MOCK_ACCOUNT.primaryEmail.email,
|
||||
clickHandler,
|
||||
}: Partial<LinkRememberPasswordProps>) => (
|
||||
<LocationProvider>
|
||||
<LinkRememberPassword {...{ email }} />
|
||||
<LinkRememberPassword {...{ email, clickHandler }} />
|
||||
</LocationProvider>
|
||||
);
|
||||
|
||||
|
@ -55,4 +68,17 @@ describe('LinkRememberPassword', () => {
|
|||
`/?client_id=123&prefillEmail=${encodeURIComponent(MOCK_EMAIL)}`
|
||||
);
|
||||
});
|
||||
|
||||
it('executes a clickHandler if passed in as prop', async () => {
|
||||
const mockClickHandler = jest.fn();
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderWithLocalizationProvider(<Subject clickHandler={mockClickHandler} />);
|
||||
|
||||
await waitFor(() =>
|
||||
user.click(screen.getByRole('link', { name: /^Sign in/ }))
|
||||
);
|
||||
|
||||
expect(mockClickHandler).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,28 +3,46 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { FtlMsg } from 'fxa-react/lib/utils';
|
||||
import { FtlMsg, hardNavigate } from 'fxa-react/lib/utils';
|
||||
import { useLocation } from '@reach/router';
|
||||
import { isEmailValid } from 'fxa-shared/email/helpers';
|
||||
|
||||
export type LinkRememberPasswordProps = {
|
||||
email?: string;
|
||||
forceAuth?: boolean;
|
||||
clickHandler?: () => void;
|
||||
};
|
||||
|
||||
const LinkRememberPassword = ({ email }: LinkRememberPasswordProps) => {
|
||||
const LinkRememberPassword = ({
|
||||
email,
|
||||
clickHandler,
|
||||
}: LinkRememberPasswordProps) => {
|
||||
let linkHref: string;
|
||||
const location = useLocation();
|
||||
const params = new URLSearchParams(location.search);
|
||||
let linkHref: string;
|
||||
params.delete('email');
|
||||
params.delete('hasLinkedAccount');
|
||||
params.delete('hasPassword');
|
||||
params.delete('showReactApp');
|
||||
|
||||
if (email && isEmailValid(email)) {
|
||||
params.set('prefillEmail', email);
|
||||
// react and backbone signin handle email/prefill params differently so
|
||||
// go back to index - any errors (like throttling) will be shown there on submit
|
||||
linkHref = `/?${params}`;
|
||||
linkHref = `/?${params.toString()}`;
|
||||
} else {
|
||||
linkHref = params.size > 0 ? `/?${params}` : '/';
|
||||
linkHref = params.size > 0 ? `/?${params.toString()}` : '/';
|
||||
}
|
||||
|
||||
const handleClick = (
|
||||
event: React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||
) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (clickHandler) {
|
||||
// additional optional click handlong behavior
|
||||
clickHandler();
|
||||
}
|
||||
hardNavigate(linkHref);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap gap-2 justify-center text-sm mt-6">
|
||||
<FtlMsg id="remember-password-text">
|
||||
|
@ -32,7 +50,12 @@ const LinkRememberPassword = ({ email }: LinkRememberPasswordProps) => {
|
|||
</FtlMsg>
|
||||
<FtlMsg id="remember-password-signin-link">
|
||||
{/* TODO in FXA-8636 replace with Link component */}
|
||||
<a href={linkHref} className="link-blue" id="remember-password">
|
||||
<a
|
||||
href={linkHref}
|
||||
className="link-blue"
|
||||
id="remember-password"
|
||||
onClick={handleClick}
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
</FtlMsg>
|
||||
|
|
|
@ -21,7 +21,7 @@ jest.mock('../../lib/metrics', () => ({
|
|||
jest.mock('../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
resetPassword: { createNewSuccess: jest.fn() },
|
||||
passwordReset: { createNewSuccess: jest.fn() },
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -36,7 +36,7 @@ describe('Ready', () => {
|
|||
// });
|
||||
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.createNewSuccess as jest.Mock).mockClear();
|
||||
(GleanMetrics.passwordReset.createNewSuccess as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
it('renders as expected with default values', () => {
|
||||
|
@ -139,7 +139,7 @@ describe('Ready', () => {
|
|||
it('emits a metrics event on render', () => {
|
||||
renderWithLocalizationProvider(<Ready {...{ viewName, isSignedIn }} />);
|
||||
expect(usePageViewEvent).toHaveBeenCalledWith(viewName, REACT_ENTRYPOINT);
|
||||
expect(GleanMetrics.resetPassword.createNewSuccess).toHaveBeenCalledTimes(
|
||||
expect(GleanMetrics.passwordReset.createNewSuccess).toHaveBeenCalledTimes(
|
||||
1
|
||||
);
|
||||
});
|
||||
|
|
|
@ -96,7 +96,7 @@ const Ready = ({
|
|||
|
||||
useEffect(() => {
|
||||
if (viewName === 'reset-password-confirmed') {
|
||||
GleanMetrics.resetPassword.createNewSuccess();
|
||||
GleanMetrics.passwordReset.createNewSuccess();
|
||||
}
|
||||
}, [viewName]);
|
||||
|
||||
|
|
|
@ -234,6 +234,9 @@ const recordEventMetric = (
|
|||
case 'login_totp_code_success_view':
|
||||
login.totpCodeSuccessView.record();
|
||||
break;
|
||||
case 'password_reset_create_new_recovery_key_message_click':
|
||||
passwordReset.createNewRecoveryKeyMessageClick.record();
|
||||
break;
|
||||
case 'password_reset_create_new_submit':
|
||||
passwordReset.createNewSubmit.record();
|
||||
break;
|
||||
|
@ -243,6 +246,24 @@ const recordEventMetric = (
|
|||
case 'password_reset_create_new_view':
|
||||
passwordReset.createNewView.record();
|
||||
break;
|
||||
case 'password_reset_email_confirmation_different_account':
|
||||
passwordReset.emailConfirmationDifferentAccount.record();
|
||||
break;
|
||||
case 'password_reset_email_confirmation_signin':
|
||||
passwordReset.emailConfirmationSignin.record();
|
||||
break;
|
||||
case 'password_reset_email_confirmation_submit':
|
||||
passwordReset.emailConfirmationSubmit.record();
|
||||
break;
|
||||
case 'password_reset_email_confirmation_view':
|
||||
passwordReset.emailConfirmationView.record();
|
||||
break;
|
||||
case 'password_reset_email_confirmation_resend_code':
|
||||
passwordReset.emailConfirmationResendCode.record();
|
||||
break;
|
||||
case 'password_reset_recovery_key_cannot_find':
|
||||
passwordReset.recoveryKeyCannotFind.record();
|
||||
break;
|
||||
case 'password_reset_recovery_key_create_new_submit':
|
||||
passwordReset.recoveryKeyCreateNewSubmit.record();
|
||||
break;
|
||||
|
|
|
@ -35,7 +35,7 @@ jest.mock('../../../lib/metrics', () => ({
|
|||
logViewEvent: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../../lib/glean', () => ({
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
recoveryKeyView: jest.fn(),
|
||||
recoveryKeySubmit: jest.fn(),
|
||||
},
|
||||
|
@ -154,7 +154,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
.spyOn(console, 'warn')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
(GleanMetrics.resetPassword.recoveryKeyView as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.recoveryKeyView as jest.Mock).mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -171,7 +171,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
'The link you clicked was missing characters, and may have been broken by your email client. Copy the address carefully, and try again.'
|
||||
);
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.recoveryKeyView).not.toHaveBeenCalled();
|
||||
expect(GleanMetrics.passwordReset.recoveryKeyView).not.toHaveBeenCalled();
|
||||
});
|
||||
it('with missing code', async () => {
|
||||
renderSubject({ params: paramsWithMissingCode });
|
||||
|
@ -180,7 +180,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
name: 'Reset password link damaged',
|
||||
});
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.recoveryKeyView).not.toHaveBeenCalled();
|
||||
expect(GleanMetrics.passwordReset.recoveryKeyView).not.toHaveBeenCalled();
|
||||
});
|
||||
it('with missing email', async () => {
|
||||
renderSubject({ params: paramsWithMissingEmail });
|
||||
|
@ -189,7 +189,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
name: 'Reset password link damaged',
|
||||
});
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.recoveryKeyView).not.toHaveBeenCalled();
|
||||
expect(GleanMetrics.passwordReset.recoveryKeyView).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -349,8 +349,8 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
|
||||
describe('emits metrics events', () => {
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.recoveryKeyView as jest.Mock).mockReset();
|
||||
(GleanMetrics.resetPassword.recoveryKeySubmit as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.recoveryKeyView as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.recoveryKeySubmit as jest.Mock).mockReset();
|
||||
});
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
it('on engage, submit, success', async () => {
|
||||
|
@ -361,7 +361,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
|
||||
expect(logPageViewEvent).toHaveBeenCalledWith(viewName, REACT_ENTRYPOINT);
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeyView as jest.Mock
|
||||
GleanMetrics.passwordReset.recoveryKeyView as jest.Mock
|
||||
).toHaveBeenCalledTimes(1);
|
||||
|
||||
await typeByLabelText('Enter account recovery key')(MOCK_RECOVERY_KEY);
|
||||
|
@ -388,7 +388,7 @@ describe('PageAccountRecoveryConfirmKey', () => {
|
|||
);
|
||||
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeySubmit as jest.Mock
|
||||
GleanMetrics.passwordReset.recoveryKeySubmit as jest.Mock
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -63,7 +63,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
|
||||
setShowLoadingSpinner(false);
|
||||
logPageViewEvent(viewName, REACT_ENTRYPOINT);
|
||||
GleanMetrics.resetPassword.recoveryKeyView();
|
||||
GleanMetrics.passwordReset.recoveryKeyView();
|
||||
} else {
|
||||
setLinkStatus(LinkStatus.expired);
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
setIsLoading(true);
|
||||
setBannerMessage(undefined);
|
||||
logViewEvent('flow', `${viewName}.submit`, REACT_ENTRYPOINT);
|
||||
GleanMetrics.resetPassword.recoveryKeySubmit();
|
||||
GleanMetrics.passwordReset.recoveryKeySubmit();
|
||||
|
||||
// if the submitted key does not match the expected format,
|
||||
// abort before submitting to the auth server
|
||||
|
|
|
@ -34,7 +34,7 @@ import GleanMetrics from '../../../lib/glean';
|
|||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
recoveryKeyCreatePasswordView: jest.fn(),
|
||||
recoveryKeyCreatePasswordSubmit: jest.fn(),
|
||||
},
|
||||
|
@ -219,7 +219,7 @@ describe('AccountRecoveryResetPassword page', () => {
|
|||
REACT_ENTRYPOINT
|
||||
);
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordView
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordView
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -256,7 +256,7 @@ describe('AccountRecoveryResetPassword page', () => {
|
|||
'verification.success'
|
||||
);
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordSubmit
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordSubmit
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ const AccountRecoveryResetPassword = ({
|
|||
integration,
|
||||
}: AccountRecoveryResetPasswordProps) => {
|
||||
usePageViewEvent(viewName, REACT_ENTRYPOINT);
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordView();
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordView();
|
||||
|
||||
const account = useAccount();
|
||||
const navigate = useNavigate();
|
||||
|
@ -199,7 +199,7 @@ const AccountRecoveryResetPassword = ({
|
|||
async function onSubmit(data: AccountRecoveryResetPasswordFormData) {
|
||||
const password = data.newPassword;
|
||||
const email = verificationInfo.email;
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordSubmit();
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordSubmit();
|
||||
|
||||
try {
|
||||
const options = {
|
||||
|
|
|
@ -48,7 +48,7 @@ jest.mock('../../../lib/metrics', () => ({
|
|||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
resetPassword: { createNewView: jest.fn(), createNewSubmit: jest.fn() },
|
||||
passwordReset: { createNewView: jest.fn(), createNewSubmit: jest.fn() },
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -122,7 +122,7 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
session = mockSession(true, false);
|
||||
|
||||
(GleanMetrics.resetPassword.createNewView as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.createNewView as jest.Mock).mockReset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -202,7 +202,7 @@ describe('CompleteResetPassword page', () => {
|
|||
'The link you clicked was missing characters, and may have been broken by your email client. Copy the address carefully, and try again.'
|
||||
);
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.createNewView).not.toBeCalled();
|
||||
expect(GleanMetrics.passwordReset.createNewView).not.toBeCalled();
|
||||
});
|
||||
it('with missing code', async () => {
|
||||
render(<Subject params={paramsWithMissingCode} />, account);
|
||||
|
@ -211,7 +211,7 @@ describe('CompleteResetPassword page', () => {
|
|||
name: 'Reset password link damaged',
|
||||
});
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.createNewView).not.toBeCalled();
|
||||
expect(GleanMetrics.passwordReset.createNewView).not.toBeCalled();
|
||||
});
|
||||
it('with missing email', async () => {
|
||||
render(<Subject params={paramsWithMissingEmail} />, account);
|
||||
|
@ -220,7 +220,7 @@ describe('CompleteResetPassword page', () => {
|
|||
name: 'Reset password link damaged',
|
||||
});
|
||||
expect(mockConsoleWarn).toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.createNewView).not.toBeCalled();
|
||||
expect(GleanMetrics.passwordReset.createNewView).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -236,7 +236,7 @@ describe('CompleteResetPassword page', () => {
|
|||
'complete-reset-password',
|
||||
REACT_ENTRYPOINT
|
||||
);
|
||||
expect(GleanMetrics.resetPassword.createNewView).toBeCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.createNewView).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
|
@ -357,7 +357,7 @@ describe('CompleteResetPassword page', () => {
|
|||
expect(
|
||||
(account.completeResetPassword as jest.Mock).mock.calls[0]
|
||||
).toBeTruthy();
|
||||
expect(GleanMetrics.resetPassword.createNewSubmit).toBeCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.createNewSubmit).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('submits with emailToHashWith if present', async () => {
|
||||
|
|
|
@ -154,7 +154,7 @@ const CompleteResetPassword = ({
|
|||
const renderCompleteResetPassword = () => {
|
||||
setShowLoadingSpinner(false);
|
||||
logPageViewEvent(viewName, REACT_ENTRYPOINT);
|
||||
GleanMetrics.resetPassword.createNewView();
|
||||
GleanMetrics.passwordReset.createNewView();
|
||||
};
|
||||
|
||||
/* When the user clicks the confirm password reset link from their email, we check
|
||||
|
@ -214,7 +214,7 @@ const CompleteResetPassword = ({
|
|||
// how account password hashing works previously.
|
||||
const emailToUse = emailToHashWith || email;
|
||||
|
||||
GleanMetrics.resetPassword.createNewSubmit();
|
||||
GleanMetrics.passwordReset.createNewSubmit();
|
||||
|
||||
const accountResetData = await account.completeResetPassword(
|
||||
keyStretchExperiment.queryParamModel.isV2(config),
|
||||
|
|
|
@ -27,7 +27,7 @@ jest.mock('../../../lib/metrics', () => ({
|
|||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
recoveryKeyResetSuccessView: jest.fn(),
|
||||
},
|
||||
},
|
||||
|
@ -135,7 +135,7 @@ describe('ResetPasswordWithRecoveryKeyVerified', () => {
|
|||
REACT_ENTRYPOINT
|
||||
);
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeyResetSuccessView
|
||||
GleanMetrics.passwordReset.recoveryKeyResetSuccessView
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ const ResetPasswordWithRecoveryKeyVerified = ({
|
|||
integration,
|
||||
}: ResetPasswordWithRecoveryKeyVerifiedProps & RouteComponentProps) => {
|
||||
usePageViewEvent(viewName, REACT_ENTRYPOINT);
|
||||
GleanMetrics.resetPassword.recoveryKeyResetSuccessView();
|
||||
GleanMetrics.passwordReset.recoveryKeyResetSuccessView();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ jest.mock('@reach/router', () => ({
|
|||
|
||||
jest.mock('../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: { resetPassword: { view: jest.fn(), submit: jest.fn() } },
|
||||
default: { passwordReset: { view: jest.fn(), submit: jest.fn() } },
|
||||
}));
|
||||
|
||||
const route = '/reset_password';
|
||||
|
@ -85,8 +85,8 @@ describe('PageResetPassword', () => {
|
|||
// });
|
||||
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.view as jest.Mock).mockClear();
|
||||
(GleanMetrics.resetPassword.submit as jest.Mock).mockClear();
|
||||
(GleanMetrics.passwordReset.view as jest.Mock).mockClear();
|
||||
(GleanMetrics.passwordReset.submit as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
it('renders as expected', async () => {
|
||||
|
@ -127,7 +127,7 @@ describe('PageResetPassword', () => {
|
|||
render(<ResetPasswordWithWebIntegration />);
|
||||
await screen.findByText('Reset password');
|
||||
expect(usePageViewEvent).toHaveBeenCalledWith(viewName, REACT_ENTRYPOINT);
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('submit success with OAuth integration', async () => {
|
||||
|
@ -155,7 +155,7 @@ describe('PageResetPassword', () => {
|
|||
fireEvent.click(await screen.findByText('Begin reset'));
|
||||
});
|
||||
|
||||
expect(GleanMetrics.resetPassword.submit).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.submit).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(account.resetPassword).toHaveBeenCalled();
|
||||
|
||||
|
@ -295,7 +295,7 @@ describe('PageResetPassword', () => {
|
|||
fireEvent.click(screen.getByRole('button', { name: 'Begin reset' }));
|
||||
await screen.findByText('Unknown account');
|
||||
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('displays an error when rate limiting kicks in', async () => {
|
||||
|
@ -333,7 +333,7 @@ describe('PageResetPassword', () => {
|
|||
'You’ve tried too many times. Please try again in 15 minutes.'
|
||||
);
|
||||
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('handles unexpected errors on submit', async () => {
|
||||
|
|
|
@ -58,7 +58,7 @@ const ResetPassword = ({
|
|||
const serviceName = integration.getServiceName();
|
||||
|
||||
useEffect(() => {
|
||||
GleanMetrics.resetPassword.view();
|
||||
GleanMetrics.passwordReset.view();
|
||||
}, []);
|
||||
|
||||
const { control, getValues, handleSubmit, register } =
|
||||
|
@ -154,7 +154,7 @@ const ResetPassword = ({
|
|||
ftlMsgResolver.getMsg('auth-error-1011', 'Valid email required')
|
||||
);
|
||||
} else {
|
||||
GleanMetrics.resetPassword.submit();
|
||||
GleanMetrics.passwordReset.submit();
|
||||
submitEmail(sanitizedEmail, {
|
||||
metricsContext: queryParamsToMetricsContext(
|
||||
flowQueryParams as unknown as Record<string, string>
|
||||
|
|
|
@ -16,7 +16,7 @@ const mockVerifyRecoveryKey = jest.fn((_recoveryKey: string) =>
|
|||
);
|
||||
|
||||
jest.mock('../../../lib/glean', () => ({
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
recoveryKeyView: jest.fn(),
|
||||
recoveryKeySubmit: jest.fn(),
|
||||
},
|
||||
|
@ -24,8 +24,8 @@ jest.mock('../../../lib/glean', () => ({
|
|||
|
||||
describe('AccountRecoveryConfirmKey', () => {
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.recoveryKeyView as jest.Mock).mockReset();
|
||||
(GleanMetrics.resetPassword.recoveryKeySubmit as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.recoveryKeyView as jest.Mock).mockReset();
|
||||
(GleanMetrics.passwordReset.recoveryKeySubmit as jest.Mock).mockReset();
|
||||
mockVerifyRecoveryKey.mockClear();
|
||||
});
|
||||
|
||||
|
@ -85,7 +85,7 @@ describe('AccountRecoveryConfirmKey', () => {
|
|||
|
||||
expect(mockVerifyRecoveryKey).toHaveBeenCalled();
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeySubmit
|
||||
GleanMetrics.passwordReset.recoveryKeySubmit
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
GleanMetrics.resetPassword.recoveryKeyView();
|
||||
GleanMetrics.passwordReset.recoveryKeyView();
|
||||
}, []);
|
||||
|
||||
const onSubmit = () => {
|
||||
|
@ -64,7 +64,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
|
||||
if (recoveryKey.length === 32 && isBase32Crockford(recoveryKey)) {
|
||||
setIsSubmitting(true);
|
||||
GleanMetrics.resetPassword.recoveryKeySubmit();
|
||||
GleanMetrics.passwordReset.recoveryKeySubmit();
|
||||
verifyRecoveryKey(recoveryKey);
|
||||
} else {
|
||||
// if the submitted key does not match the expected format,
|
||||
|
@ -157,6 +157,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
token,
|
||||
uid,
|
||||
}}
|
||||
onClick={() => GleanMetrics.passwordReset.recoveryKeyCannotFind()}
|
||||
>
|
||||
Don’t have an account recovery key?
|
||||
</Link>
|
||||
|
|
|
@ -141,7 +141,7 @@ const CompleteResetPasswordContainer = ({
|
|||
const emailToUse = emailToHashWith || email;
|
||||
|
||||
if (hasConfirmedRecoveryKey) {
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordSubmit();
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordSubmit();
|
||||
const accountResetData = await resetPasswordWithRecoveryKey(
|
||||
accountResetToken,
|
||||
emailToUse,
|
||||
|
@ -153,7 +153,7 @@ const CompleteResetPasswordContainer = ({
|
|||
notifyBrowserOfSignin(accountResetData);
|
||||
handleNavigationWithRecoveryKey();
|
||||
} else if (isResetWithoutRecoveryKey) {
|
||||
GleanMetrics.resetPassword.createNewSubmit();
|
||||
GleanMetrics.passwordReset.createNewSubmit();
|
||||
const accountResetData = await resetPasswordWithoutRecoveryKey(
|
||||
code,
|
||||
emailToUse,
|
||||
|
|
|
@ -16,7 +16,7 @@ const mockSubmitNewPassword = jest.fn((newPassword: string) =>
|
|||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
createNewView: jest.fn(),
|
||||
recoveryKeyCreatePasswordView: jest.fn(),
|
||||
},
|
||||
|
@ -25,9 +25,9 @@ jest.mock('../../../lib/glean', () => ({
|
|||
|
||||
describe('CompleteResetPassword page', () => {
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.createNewView as jest.Mock).mockClear();
|
||||
(GleanMetrics.passwordReset.createNewView as jest.Mock).mockClear();
|
||||
(
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordView as jest.Mock
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordView as jest.Mock
|
||||
).mockClear();
|
||||
mockSubmitNewPassword.mockClear();
|
||||
});
|
||||
|
@ -72,7 +72,7 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
it('sends the expected metrics on render', () => {
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
expect(GleanMetrics.resetPassword.createNewView).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.createNewView).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -118,7 +118,7 @@ describe('CompleteResetPassword page', () => {
|
|||
it('sends the expected metrics on render', () => {
|
||||
renderWithLocalizationProvider(<Subject hasConfirmedRecoveryKey />);
|
||||
expect(
|
||||
GleanMetrics.resetPassword.recoveryKeyCreatePasswordView
|
||||
GleanMetrics.passwordReset.recoveryKeyCreatePasswordView
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,8 +31,8 @@ const CompleteResetPassword = ({
|
|||
|
||||
useEffect(() => {
|
||||
hasConfirmedRecoveryKey
|
||||
? GleanMetrics.resetPassword.recoveryKeyCreatePasswordView()
|
||||
: GleanMetrics.resetPassword.createNewView();
|
||||
? GleanMetrics.passwordReset.recoveryKeyCreatePasswordView()
|
||||
: GleanMetrics.passwordReset.createNewView();
|
||||
}, [hasConfirmedRecoveryKey]);
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
@ -76,6 +76,9 @@ const CompleteResetPassword = ({
|
|||
to={`/account_recovery_confirm_key${location.search}`}
|
||||
state={locationState}
|
||||
className="link-white underline-offset-4"
|
||||
onClick={() =>
|
||||
GleanMetrics.passwordReset.createNewClickRecoveryKeyMessage()
|
||||
}
|
||||
>
|
||||
Reset your password with your account recovery key.
|
||||
</Link>
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { ResendStatus } from '../../../lib/types';
|
||||
import { useNavigateWithQuery } from '../../../lib/hooks/useNavigateWithQuery';
|
||||
import { getLocalizedErrorMessage } from '../../../lib/error-utils';
|
||||
import GleanMetrics from '../../../lib/glean';
|
||||
|
||||
const ConfirmResetPasswordContainer = (_: RouteComponentProps) => {
|
||||
const [resendStatus, setResendStatus] = useState<ResendStatus>(
|
||||
|
@ -91,6 +92,7 @@ const ConfirmResetPasswordContainer = (_: RouteComponentProps) => {
|
|||
setResendStatus(ResendStatus['not sent']);
|
||||
const options = { metricsContext };
|
||||
try {
|
||||
GleanMetrics.passwordReset.emailConfirmationSubmit();
|
||||
const { code, emailToHashWith, token, uid } =
|
||||
await authClient.passwordForgotVerifyOtp(email, otpCode, options);
|
||||
const { exists: recoveryKeyExists, estimatedSyncDeviceCount } =
|
||||
|
|
|
@ -7,19 +7,52 @@
|
|||
import React from 'react';
|
||||
import { Subject } from './mocks';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import * as utils from 'fxa-react/lib/utils';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MOCK_EMAIL } from '../../mocks';
|
||||
import GleanMetrics from '../../../lib/glean';
|
||||
|
||||
// add Glean mocks
|
||||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
passwordReset: {
|
||||
emailConfirmationView: jest.fn(),
|
||||
emailConfirmationResendCode: jest.fn(),
|
||||
emailConfirmationDifferentAccount: jest.fn(),
|
||||
emailConfirmationSignin: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('fxa-react/lib/utils', () => ({
|
||||
...jest.requireActual('fxa-react/lib/utils'),
|
||||
hardNavigate: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockResendCode = jest.fn(() => Promise.resolve(true));
|
||||
const mockVerifyCode = jest.fn((code: string) => Promise.resolve());
|
||||
|
||||
describe('ConfirmResetPassword', () => {
|
||||
let locationAssignSpy: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockResendCode.mockClear();
|
||||
mockVerifyCode.mockClear();
|
||||
jest.clearAllMocks();
|
||||
|
||||
locationAssignSpy = jest.fn();
|
||||
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
// mock content server url for URL constructor
|
||||
origin: 'http://localhost:3030',
|
||||
assign: locationAssignSpy,
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
locationAssignSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('renders as expected', async () => {
|
||||
|
@ -45,6 +78,18 @@ describe('ConfirmResetPassword', () => {
|
|||
expect(links[2]).toHaveTextContent('Use a different account');
|
||||
});
|
||||
|
||||
it('emits the expected metrics event on render', async () => {
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
await expect(
|
||||
screen.getByRole('heading', { name: 'Check your email' })
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
GleanMetrics.passwordReset.emailConfirmationView
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('submits with valid code', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithLocalizationProvider(<Subject verifyCode={mockVerifyCode} />);
|
||||
|
@ -66,6 +111,20 @@ describe('ConfirmResetPassword', () => {
|
|||
expect(mockVerifyCode).toHaveBeenCalledWith('12345678');
|
||||
});
|
||||
|
||||
it('handles click on signin', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
const signinLink = screen.getByRole('link', {
|
||||
name: 'Sign in',
|
||||
});
|
||||
|
||||
await waitFor(() => user.click(signinLink));
|
||||
expect(
|
||||
GleanMetrics.passwordReset.emailConfirmationSignin
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('handles resend code', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithLocalizationProvider(<Subject resendCode={mockResendCode} />);
|
||||
|
@ -76,6 +135,9 @@ describe('ConfirmResetPassword', () => {
|
|||
|
||||
await waitFor(() => user.click(resendButton));
|
||||
expect(mockResendCode).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
GleanMetrics.passwordReset.emailConfirmationResendCode
|
||||
).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
|
@ -83,4 +145,22 @@ describe('ConfirmResetPassword', () => {
|
|||
)
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('handles Use different account link', async () => {
|
||||
let hardNavigateSpy: jest.SpyInstance;
|
||||
hardNavigateSpy = jest
|
||||
.spyOn(utils, 'hardNavigate')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
const user = userEvent.setup();
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
|
||||
await waitFor(() =>
|
||||
user.click(screen.getByRole('link', { name: /^Use a different account/ }))
|
||||
);
|
||||
expect(hardNavigateSpy).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
GleanMetrics.passwordReset.emailConfirmationDifferentAccount
|
||||
).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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 React, { useEffect } from 'react';
|
||||
import AppLayout from '../../../components/AppLayout';
|
||||
import FormVerifyTotp from '../../../components/FormVerifyTotp';
|
||||
import { ConfirmResetPasswordProps } from './interfaces';
|
||||
|
@ -13,6 +13,7 @@ import { FtlMsg, hardNavigate } from 'fxa-react/lib/utils';
|
|||
import { ResendEmailSuccessBanner } from '../../../components/Banner';
|
||||
import { ResendStatus } from '../../../lib/types';
|
||||
import { EmailCodeImage } from '../../../components/images';
|
||||
import GleanMetrics from '../../../lib/glean';
|
||||
|
||||
const ConfirmResetPassword = ({
|
||||
email,
|
||||
|
@ -23,6 +24,10 @@ const ConfirmResetPassword = ({
|
|||
setResendStatus,
|
||||
verifyCode,
|
||||
}: ConfirmResetPasswordProps & RouteComponentProps) => {
|
||||
useEffect(() => {
|
||||
GleanMetrics.passwordReset.emailConfirmationView();
|
||||
}, []);
|
||||
|
||||
const ftlMsgResolver = useFtlMsgResolver();
|
||||
const location = useLocation();
|
||||
|
||||
|
@ -39,12 +44,17 @@ const ConfirmResetPassword = ({
|
|||
|
||||
const handleResend = async () => {
|
||||
setResendStatus(ResendStatus['not sent']);
|
||||
GleanMetrics.passwordReset.emailConfirmationResendCode();
|
||||
const result = await resendCode();
|
||||
if (result === true) {
|
||||
setResendStatus(ResendStatus.sent);
|
||||
}
|
||||
};
|
||||
|
||||
const signinClickHandler = () => {
|
||||
GleanMetrics.passwordReset.emailConfirmationSignin();
|
||||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<FtlMsg id="password-reset-flow-heading">
|
||||
|
@ -74,7 +84,7 @@ const ConfirmResetPassword = ({
|
|||
verifyCode,
|
||||
}}
|
||||
/>
|
||||
<LinkRememberPassword {...{ email }} />
|
||||
<LinkRememberPassword {...{ email }} clickHandler={signinClickHandler} />
|
||||
<div className="flex justify-between mt-8 text-sm">
|
||||
<FtlMsg id="confirm-reset-password-otp-resend-code-button">
|
||||
<button type="button" className="link-blue" onClick={handleResend}>
|
||||
|
@ -87,6 +97,7 @@ const ConfirmResetPassword = ({
|
|||
className="text-sm link-blue"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
GleanMetrics.passwordReset.emailConfirmationDifferentAccount();
|
||||
const params = new URLSearchParams(location.search);
|
||||
// Tell content-server to stay on index and prefill the email
|
||||
params.set('prefillEmail', email);
|
||||
|
|
|
@ -13,7 +13,7 @@ import { MOCK_EMAIL } from '../../mocks';
|
|||
|
||||
jest.mock('../../../lib/glean', () => ({
|
||||
__esModule: true,
|
||||
default: { resetPassword: { view: jest.fn(), submit: jest.fn() } },
|
||||
default: { passwordReset: { view: jest.fn(), submit: jest.fn() } },
|
||||
}));
|
||||
|
||||
const mockRequestResetPasswordCode = jest.fn((email: string) =>
|
||||
|
@ -22,9 +22,7 @@ const mockRequestResetPasswordCode = jest.fn((email: string) =>
|
|||
|
||||
describe('ResetPassword', () => {
|
||||
beforeEach(() => {
|
||||
(GleanMetrics.resetPassword.view as jest.Mock).mockClear();
|
||||
(GleanMetrics.resetPassword.submit as jest.Mock).mockClear();
|
||||
mockRequestResetPasswordCode.mockClear();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('renders', () => {
|
||||
|
@ -47,7 +45,7 @@ describe('ResetPassword', () => {
|
|||
it('emits a Glean event on render', async () => {
|
||||
renderWithLocalizationProvider(<Subject />);
|
||||
await expect(screen.getByRole('heading', { level: 1 })).toBeVisible();
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -68,8 +66,8 @@ describe('ResetPassword', () => {
|
|||
|
||||
expect(mockRequestResetPasswordCode).toBeCalledWith(MOCK_EMAIL);
|
||||
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.resetPassword.submit).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.submit).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('trims leading space in email', async () => {
|
||||
|
@ -87,8 +85,8 @@ describe('ResetPassword', () => {
|
|||
await waitFor(() => user.click(screen.getByRole('button')));
|
||||
|
||||
expect(mockRequestResetPasswordCode).toBeCalledWith(MOCK_EMAIL);
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.resetPassword.submit).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.submit).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('handles errors', () => {
|
||||
|
@ -103,8 +101,8 @@ describe('ResetPassword', () => {
|
|||
|
||||
expect(screen.getByText('Valid email required')).toBeVisible();
|
||||
expect(mockRequestResetPasswordCode).not.toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.resetPassword.submit).not.toHaveBeenCalled();
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.submit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('with an invalid email', async () => {
|
||||
|
@ -120,8 +118,8 @@ describe('ResetPassword', () => {
|
|||
|
||||
expect(screen.getByText('Valid email required')).toBeVisible();
|
||||
expect(mockRequestResetPasswordCode).not.toBeCalled();
|
||||
expect(GleanMetrics.resetPassword.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.resetPassword.submit).not.toHaveBeenCalled();
|
||||
expect(GleanMetrics.passwordReset.view).toHaveBeenCalledTimes(1);
|
||||
expect(GleanMetrics.passwordReset.submit).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,7 +32,7 @@ const ResetPassword = ({
|
|||
const ftlMsgResolver = useFtlMsgResolver();
|
||||
|
||||
useEffect(() => {
|
||||
GleanMetrics.resetPassword.view();
|
||||
GleanMetrics.passwordReset.view();
|
||||
}, []);
|
||||
|
||||
const { control, getValues, handleSubmit, register } =
|
||||
|
@ -55,7 +55,7 @@ const ResetPassword = ({
|
|||
ftlMsgResolver.getMsg('auth-error-1011', 'Valid email required')
|
||||
);
|
||||
} else {
|
||||
GleanMetrics.resetPassword.submit();
|
||||
GleanMetrics.passwordReset.submit();
|
||||
await requestResetPasswordCode(email);
|
||||
}
|
||||
setIsSubmitting(false);
|
||||
|
|
|
@ -621,6 +621,24 @@ login:
|
|||
data_sensitivity:
|
||||
- interaction
|
||||
password_reset:
|
||||
create_new_recovery_key_message_click:
|
||||
type: event
|
||||
description: |
|
||||
Reset Password Create New Password See Recovery Key Question Click
|
||||
User clicks the button for "reset your password with your recovery key"'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
create_new_submit:
|
||||
type: event
|
||||
description: |
|
||||
|
@ -675,6 +693,114 @@ password_reset:
|
|||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
email_confirmation_different_account:
|
||||
type: event
|
||||
description: |
|
||||
Forgot Password Confirmation Code Use a different account
|
||||
User clicks the "use a different account" button on the "Enter Confirmation Code" screen'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
email_confirmation_signin:
|
||||
type: event
|
||||
description: |
|
||||
Forgot Password Confirmation Code Sign In
|
||||
User clicks the "sign in" button on the "Enter Confirmation Code" screen'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
email_confirmation_submit:
|
||||
type: event
|
||||
description: |
|
||||
Forgot Password Confirmation Code Submit
|
||||
User clicks the "Continue" button on the "Enter Confirmation Code" screen'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
email_confirmation_view:
|
||||
type: event
|
||||
description: |
|
||||
Forgot Password Confirmation Code View
|
||||
User views the "Enter Confirmation Code" screen'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
email_confirmation_resend_code:
|
||||
type: event
|
||||
description: |
|
||||
Forgot Password Confirmation Code Resend
|
||||
User clicks the "resend code" button on the "Enter Confirmation Code" screen'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
recovery_key_cannot_find:
|
||||
type: event
|
||||
description: |
|
||||
Reset Password Can't Find Key
|
||||
User clicks the "Can't find your account recovery key?" button on the confirm reccovery key page'
|
||||
send_in_pings:
|
||||
- events
|
||||
notification_emails:
|
||||
- vzare@mozilla.com
|
||||
- fxa-staff@mozilla.com
|
||||
bugs:
|
||||
- https://mozilla-hub.atlassian.net/browse/FXA-9529
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1830504
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1844121
|
||||
expires: never
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
recovery_key_create_new_submit:
|
||||
type: event
|
||||
description: |
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/* 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/. */
|
||||
|
||||
// AUTOGENERATED BY glean_parser v14.0.1. DO NOT EDIT. DO NOT COMMIT.
|
||||
|
||||
import EventMetricType from '@mozilla/glean/private/metrics/event';
|
||||
|
||||
/**
|
||||
* User engaged on the "Connect another device" screen with choice options,
|
||||
* selecting either of "I already have FF for mobile" or "I don't have FF for
|
||||
* mobile", which is provided in the 'reason' for this event
|
||||
*
|
||||
* Generated from `cad_firefox.choice_engage`.
|
||||
*/
|
||||
export const choiceEngage = new EventMetricType<{
|
||||
reason?: string;
|
||||
}>(
|
||||
{
|
||||
category: 'cad_firefox',
|
||||
name: 'choice_engage',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
['reason']
|
||||
);
|
||||
|
||||
/**
|
||||
* User submitted on the "Connect another device" screen with choice options,
|
||||
* submitting either of "I already have FF for mobile" or "I don't have FF for
|
||||
* mobile", which is provided in the 'reason' for this event
|
||||
*
|
||||
* Generated from `cad_firefox.choice_submit`.
|
||||
*/
|
||||
export const choiceSubmit = new EventMetricType<{
|
||||
reason?: string;
|
||||
}>(
|
||||
{
|
||||
category: 'cad_firefox',
|
||||
name: 'choice_submit',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
['reason']
|
||||
);
|
||||
|
||||
/**
|
||||
* User viewed the "Connect another device" screen with choice options to download
|
||||
* FF for mobile or not
|
||||
*
|
||||
* Generated from `cad_firefox.choice_view`.
|
||||
*/
|
||||
export const choiceView = new EventMetricType(
|
||||
{
|
||||
category: 'cad_firefox',
|
||||
name: 'choice_view',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* User clicked the "Continue to sync" button on the "Download Firefox for mobile"
|
||||
* screen
|
||||
*
|
||||
* Generated from `cad_firefox.sync_device_submit`.
|
||||
*/
|
||||
export const syncDeviceSubmit = new EventMetricType(
|
||||
{
|
||||
category: 'cad_firefox',
|
||||
name: 'sync_device_submit',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* User viewed the "Download Firefox for mobile" screen after choosing and
|
||||
* submitting the "I don't have Firefox for mobile" option
|
||||
*
|
||||
* Generated from `cad_firefox.view`.
|
||||
*/
|
||||
export const view = new EventMetricType(
|
||||
{
|
||||
category: 'cad_firefox',
|
||||
name: 'view',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
|
@ -80,14 +80,27 @@ export const eventsMap = {
|
|||
success: 'login_totp_code_success_view',
|
||||
},
|
||||
|
||||
resetPassword: {
|
||||
passwordReset: {
|
||||
view: 'password_reset_view',
|
||||
submit: 'password_reset_submit',
|
||||
|
||||
createNewView: 'password_reset_create_new_view',
|
||||
createNewSubmit: 'password_reset_create_new_submit',
|
||||
createNewSuccess: 'password_reset_create_new_success_view',
|
||||
createNewClickRecoveryKeyMessage:
|
||||
'password_reset_create_new_recovery_key_message_click',
|
||||
|
||||
emailConfirmationView: 'password_reset_email_confirmation_view',
|
||||
emailConfirmationSubmit: 'password_reset_email_confirmation_submit',
|
||||
emailConfirmationDifferentAccount:
|
||||
'password_reset_email_confirmation_different_account',
|
||||
emailConfirmationSignin: 'password_reset_email_confirmation_signin',
|
||||
emailConfirmationResendCode:
|
||||
'password_reset_email_confirmation_resend_code',
|
||||
|
||||
recoveryKeyView: 'password_reset_recovery_key_view',
|
||||
recoveryKeySubmit: 'password_reset_recovery_key_submit',
|
||||
recoveryKeyCannotFind: 'password_reset_recovery_key_cannot_find',
|
||||
|
||||
recoveryKeyCreatePasswordView:
|
||||
'password_reset_recovery_key_create_new_view',
|
||||
|
|
|
@ -6,6 +6,23 @@
|
|||
|
||||
import EventMetricType from '@mozilla/glean/private/metrics/event';
|
||||
|
||||
/**
|
||||
* Reset Password Create New Password See Recovery Key Question Click
|
||||
* User clicks the button for "reset your password with your recovery key"'
|
||||
*
|
||||
* Generated from `password_reset.create_new_recovery_key_message_click`.
|
||||
*/
|
||||
export const createNewRecoveryKeyMessageClick = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'create_new_recovery_key_message_click',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Create New Password Submit
|
||||
* User attemps to submit the create new password form'
|
||||
|
@ -57,6 +74,110 @@ export const createNewView = new EventMetricType(
|
|||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password Confirmation Code Use a different account
|
||||
* User clicks the "use a different account" button on the "Enter Confirmation
|
||||
* Code" screen'
|
||||
*
|
||||
* Generated from `password_reset.email_confirmation_different_account`.
|
||||
*/
|
||||
export const emailConfirmationDifferentAccount = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'email_confirmation_different_account',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password Confirmation Code Resend
|
||||
* User clicks the "resend code" button on the "Enter Confirmation Code" screen'
|
||||
*
|
||||
* Generated from `password_reset.email_confirmation_resend_code`.
|
||||
*/
|
||||
export const emailConfirmationResendCode = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'email_confirmation_resend_code',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password Confirmation Code Sign In
|
||||
* User clicks the "sign in" button on the "Enter Confirmation Code" screen'
|
||||
*
|
||||
* Generated from `password_reset.email_confirmation_signin`.
|
||||
*/
|
||||
export const emailConfirmationSignin = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'email_confirmation_signin',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password Confirmation Code Submit
|
||||
* User clicks the "Continue" button on the "Enter Confirmation Code" screen'
|
||||
*
|
||||
* Generated from `password_reset.email_confirmation_submit`.
|
||||
*/
|
||||
export const emailConfirmationSubmit = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'email_confirmation_submit',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password Confirmation Code View
|
||||
* User views the "Enter Confirmation Code" screen'
|
||||
*
|
||||
* Generated from `password_reset.email_confirmation_view`.
|
||||
*/
|
||||
export const emailConfirmationView = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'email_confirmation_view',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Reset Password Can't Find Key
|
||||
* User clicks the "Can't find your account recovery key?" button on the confirm
|
||||
* reccovery key page'
|
||||
*
|
||||
* Generated from `password_reset.recovery_key_cannot_find`.
|
||||
*/
|
||||
export const recoveryKeyCannotFind = new EventMetricType(
|
||||
{
|
||||
category: 'password_reset',
|
||||
name: 'recovery_key_cannot_find',
|
||||
sendInPings: ['events'],
|
||||
lifetime: 'ping',
|
||||
disabled: false,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Forgot Password w/ Recovery Key Create New Password Submit
|
||||
* User attempts to submit the create new password form'
|
||||
|
|
Загрузка…
Ссылка в новой задаче