diff --git a/packages/fxa-settings/src/components/AppLayout/__snapshots__/index.test.tsx.snap b/packages/fxa-settings/src/components/AppLayout/__snapshots__/index.test.tsx.snap
index 320f1afc993..6b36ea0a971 100644
--- a/packages/fxa-settings/src/components/AppLayout/__snapshots__/index.test.tsx.snap
+++ b/packages/fxa-settings/src/components/AppLayout/__snapshots__/index.test.tsx.snap
@@ -17,7 +17,7 @@ exports[` snapshots renders correctly with CMS: header background 1
exports[` snapshots renders correctly with CMS: header logo 1`] = `
@@ -29,7 +29,7 @@ exports[` snapshots renders correctly with CMS: split layout main 1
/>
`;
-exports[` snapshots renders correctly with CMS: title 1`] = `"MOCK Shared Title | Mozilla accounts"`;
+exports[` snapshots renders correctly with CMS: title 1`] = `"CMS: Shared Title | Mozilla accounts"`;
exports[` snapshots renders correctly without CMS: background wrapper 1`] = `
{
).toBeInTheDocument();
screen.getByRole('heading', {
- name: 'Sign up or sign in to your Mozilla account',
+ name: MOCK_CMS_INFO.EmailFirstPage.headline,
+ });
+ screen.getByText(MOCK_CMS_INFO.EmailFirstPage.description);
+ screen.getByRole('button', {
+ name: MOCK_CMS_INFO.EmailFirstPage.primaryButtonText,
});
- screen.getByText(
- 'Stay protected with continuous data monitoring and automatic data removal.'
- );
- screen.getByRole('button', { name: 'Continue' });
});
it('renders as expected with cms info on mobile', () => {
diff --git a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.stories.tsx b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.stories.tsx
index 12c51650c50..08033dd0cfc 100644
--- a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.stories.tsx
+++ b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.stories.tsx
@@ -6,8 +6,8 @@ import { withLocalization } from 'fxa-react/lib/storybooks';
import SetPassword from '.';
import { Meta } from '@storybook/react';
import { SetPasswordProps } from './interfaces';
-import { Subject } from './mocks';
-import { createMockIntegrationWithCms } from '../../mocks';
+import { createMockIntegration, Subject } from './mocks';
+import { createMockIntegrationWithCms, MOCK_CMS_INFO } from '../../mocks';
export default {
title: 'Pages/PostVerify/SetPassword',
@@ -24,6 +24,18 @@ const storyWithProps = ({
export const Default = storyWithProps();
+export const ThirdPartyAuthDefault = storyWithProps({
+ passwordCreationReason: 'third_party_auth',
+});
+
+export const OtpDefault = storyWithProps({
+ passwordCreationReason: 'otp',
+});
+
+export const PasskeyDefault = storyWithProps({
+ passwordCreationReason: 'passkey',
+});
+
export const WithCms = storyWithProps({
integration: createMockIntegrationWithCms(),
});
@@ -32,3 +44,51 @@ export const OtpWithCms = storyWithProps({
passwordCreationReason: 'otp',
integration: createMockIntegrationWithCms(),
});
+
+export const ThirdPartyAuthWithCms = storyWithProps({
+ passwordCreationReason: 'third_party_auth',
+ integration: createMockIntegrationWithCms(),
+});
+
+export const PasskeyWithCms = storyWithProps({
+ passwordCreationReason: 'third_party_auth',
+ integration: createMockIntegrationWithCms(),
+});
+
+const cmsIntegrationWithLegalTerms = createMockIntegration(
+ {
+ ...MOCK_CMS_INFO,
+ PostVerifySetPasswordPage: {
+ ...MOCK_CMS_INFO.SignupSetPasswordPage,
+ headline: 'VPN Headline (from cms)',
+ description: 'VPN description (from cms)',
+ },
+ },
+ {
+ legalTerms: {
+ label: 'Customized:',
+ termsOfServiceLink: 'https://www.mozilla.org/customized/terms/',
+ privacyNoticeLink: 'https://www.mozilla.org/customized/privacy/',
+ fontSize: 'default',
+ },
+ }
+);
+
+export const WithCmsAndLegalTerms = storyWithProps({
+ integration: cmsIntegrationWithLegalTerms,
+});
+
+export const OtpWithCmsAndLegalTerms = storyWithProps({
+ passwordCreationReason: 'otp',
+ integration: cmsIntegrationWithLegalTerms,
+});
+
+export const ThirdPartyWithAndCmsAndLegalTerms = storyWithProps({
+ passwordCreationReason: 'third_party_auth',
+ integration: cmsIntegrationWithLegalTerms,
+});
+
+export const PasskeyWithCmsAndLegalTerms = storyWithProps({
+ passwordCreationReason: 'passkey',
+ integration: cmsIntegrationWithLegalTerms,
+});
diff --git a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.test.tsx b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.test.tsx
index bd046e13d12..d581120a766 100644
--- a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.test.tsx
+++ b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.test.tsx
@@ -115,6 +115,51 @@ describe('SetPassword page', () => {
).toBeInTheDocument();
});
+ it('renders the description above the email to match the Signup layout', () => {
+ renderWithLocalizationProvider(
);
+
+ const description = screen.getByText(
+ 'This encrypts your data. It needs to be different from your Google or Apple account password.'
+ );
+ const email = screen.getByText(MOCK_EMAIL);
+
+ // DOCUMENT_POSITION_FOLLOWING means `email` appears after `description`.
+ expect(
+ description.compareDocumentPosition(email) &
+ Node.DOCUMENT_POSITION_FOLLOWING
+ ).toBeTruthy();
+ });
+
+ describe('terms and privacy agreement', () => {
+ it('renders the default Mozilla Terms of Service and Privacy Notice links when no custom legal terms are set', () => {
+ renderWithLocalizationProvider(
);
+
+ expect(
+ screen.getByRole('link', { name: 'Terms of Service' })
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole('link', { name: 'Privacy Notice' })
+ ).toBeInTheDocument();
+ });
+
+ it('renders the client-specific legal terms when the integration provides them', () => {
+ renderWithLocalizationProvider(
+
+ );
+
+ expect(screen.getByText(/Mozilla VPN:/)).toBeInTheDocument();
+ });
+ });
+
describe('Glean events', () => {
// First row asserts the default-arg behaviour (no prop passed); the
// others assert explicit pass-through for each non-default value.
diff --git a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.tsx b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.tsx
index 65b7dd338e3..9f17d12cf96 100644
--- a/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.tsx
+++ b/packages/fxa-settings/src/pages/PostVerify/SetPassword/index.tsx
@@ -15,6 +15,7 @@ import {
getCmsHeadlineClassName,
getCmsHeadlineStyle,
} from '../../../components/CardHeader';
+import TermsPrivacyAgreement from '../../../components/TermsPrivacyAgreement';
import GleanMetrics from '../../../lib/glean';
export const SetPassword = ({
@@ -118,8 +119,6 @@ export const SetPassword = ({
Create password to sync
)}
-
{email}
-
{bannerErrorText && (
)}
@@ -143,6 +142,8 @@ export const SetPassword = ({
)}
+
{email}
+
+
+
);
};
diff --git a/packages/fxa-settings/src/pages/PostVerify/SetPassword/interfaces.ts b/packages/fxa-settings/src/pages/PostVerify/SetPassword/interfaces.ts
index 44b9ad344f4..b6a3f88f41f 100644
--- a/packages/fxa-settings/src/pages/PostVerify/SetPassword/interfaces.ts
+++ b/packages/fxa-settings/src/pages/PostVerify/SetPassword/interfaces.ts
@@ -23,7 +23,7 @@ export type CreatePasswordHandler = (
export type PostVerifySetPasswordIntegration = Pick<
Integration,
- 'getCmsInfo' | 'isSync'
+ 'getCmsInfo' | 'isSync' | 'getLegalTerms'
>;
/**
diff --git a/packages/fxa-settings/src/pages/PostVerify/SetPassword/mocks.tsx b/packages/fxa-settings/src/pages/PostVerify/SetPassword/mocks.tsx
index 9363663e67b..4ed5e35f9cd 100644
--- a/packages/fxa-settings/src/pages/PostVerify/SetPassword/mocks.tsx
+++ b/packages/fxa-settings/src/pages/PostVerify/SetPassword/mocks.tsx
@@ -12,14 +12,19 @@ import {
import { MOCK_EMAIL } from '../../mocks';
import { mockUseFxAStatus } from '../../../lib/hooks/useFxAStatus/mocks';
import { RelierCmsInfo } from '../../../models';
+import { RelierLegalTerms } from '../../../models/integrations/relier-interfaces';
export function createMockIntegration(
cmsInfo?: RelierCmsInfo,
- { isSync = true } = {}
+ {
+ isSync = true,
+ legalTerms,
+ }: { isSync?: boolean; legalTerms?: RelierLegalTerms } = {}
): PostVerifySetPasswordIntegration {
return {
getCmsInfo: () => cmsInfo,
isSync: () => isSync,
+ getLegalTerms: () => legalTerms,
};
}
diff --git a/packages/fxa-settings/src/pages/Signin/__snapshots__/index.test.tsx.snap b/packages/fxa-settings/src/pages/Signin/__snapshots__/index.test.tsx.snap
index e8cec076f8a..b7878575053 100644
--- a/packages/fxa-settings/src/pages/Signin/__snapshots__/index.test.tsx.snap
+++ b/packages/fxa-settings/src/pages/Signin/__snapshots__/index.test.tsx.snap
@@ -2,7 +2,7 @@
exports[`Signin component snapshots - CMS renders AppLayout with CMS header logo 1`] = `

@@ -12,7 +12,7 @@ exports[`Signin component snapshots - CMS renders CardHeader with CMS content wh
`;
@@ -20,7 +20,7 @@ exports[`Signin component snapshots - CMS renders CardHeader with CMS content wh
`;
@@ -38,6 +38,6 @@ exports[`Signin component snapshots - CMS renders the CMS-styled submit button 1
style="--cta-bg: #6B4DFB; --cta-border: #6B4DFB; --cta-active: #6B4DFB; --cta-disabled: #6B4DFB; color: rgb(255, 255, 255);"
type="submit"
>
- Sign in
+ CMS: Sign in
`;
diff --git a/packages/fxa-settings/src/pages/Signin/index.test.tsx b/packages/fxa-settings/src/pages/Signin/index.test.tsx
index 9beb04e7763..24dd61dd9d3 100644
--- a/packages/fxa-settings/src/pages/Signin/index.test.tsx
+++ b/packages/fxa-settings/src/pages/Signin/index.test.tsx
@@ -1788,7 +1788,9 @@ describe('Signin component', () => {
it('renders the CMS-styled submit button', () => {
render({ integration: createMockSigninWebIntegration(cmsProps) });
- const submitButton = screen.getByRole('button', { name: 'Sign in' });
+ const submitButton = screen.getByRole('button', {
+ name: cmsProps.cmsInfo.SigninPage.primaryButtonText,
+ });
expect(submitButton).toMatchSnapshot();
});
diff --git a/packages/fxa-settings/src/pages/Signup/ConfirmSignupCode/index.test.tsx b/packages/fxa-settings/src/pages/Signup/ConfirmSignupCode/index.test.tsx
index 11fbb486cee..6ca99108896 100644
--- a/packages/fxa-settings/src/pages/Signup/ConfirmSignupCode/index.test.tsx
+++ b/packages/fxa-settings/src/pages/Signup/ConfirmSignupCode/index.test.tsx
@@ -240,11 +240,15 @@ describe('ConfirmSignupCode page', () => {
// testAllL10n(screen, bundle);
const headingEl = screen.getByRole('heading', { level: 1 });
- expect(headingEl).toHaveTextContent('Enter confirmation code');
- screen.getByText('For your Mozilla account');
+ expect(headingEl).toHaveTextContent(
+ MOCK_CMS_INFO.SignupConfirmCodePage.headline
+ );
+ screen.getByText(MOCK_CMS_INFO.SignupConfirmCodePage.description);
screen.getByLabelText('Enter 6-digit code');
- screen.getByRole('button', { name: 'Confirm' });
+ screen.getByRole('button', {
+ name: MOCK_CMS_INFO.SignupConfirmCodePage.primaryButtonText,
+ });
screen.getByRole('button', { name: 'Email new code.' });
screen.getByTestId('cms-logo');
screen.getByText(MOCK_CMS_INFO.shared.additionalAccessibilityInfo);
@@ -263,7 +267,10 @@ describe('ConfirmSignupCode page', () => {
integration,
finishOAuthFlowHandler: jest.fn().mockReturnValueOnce(tryAgainError()),
});
- submit();
+ submit(
+ MOCK_SIGNUP_CODE,
+ MOCK_CMS_INFO.SignupConfirmCodePage.primaryButtonText
+ );
await waitFor(() => {
screen.getByText(OAUTH_ERRORS.TRY_AGAIN.message);
@@ -276,7 +283,10 @@ describe('ConfirmSignupCode page', () => {
integration,
finishOAuthFlowHandler: jest.fn(),
});
- submit();
+ submit(
+ MOCK_SIGNUP_CODE,
+ MOCK_CMS_INFO.SignupConfirmCodePage.primaryButtonText
+ );
await waitFor(() => {
expect(fxaOAuthLoginSpy).not.toHaveBeenCalled();
@@ -315,7 +325,10 @@ describe('ConfirmSignupCode page', () => {
integration,
origin: 'signup',
});
- submit(MOCK_SIGNUP_CODE);
+ submit(
+ MOCK_SIGNUP_CODE,
+ MOCK_CMS_INFO.SignupConfirmCodePage.primaryButtonText
+ );
await waitFor(() => {
expect(ReactUtils.hardNavigate).toHaveBeenCalledWith(
@@ -333,7 +346,10 @@ describe('ConfirmSignupCode page', () => {
integration,
origin: 'signin',
});
- submit(MOCK_SIGNUP_CODE);
+ submit(
+ MOCK_SIGNUP_CODE,
+ MOCK_CMS_INFO.SignupConfirmCodePage.primaryButtonText
+ );
await waitFor(() => {
expect(ReactUtils.hardNavigate).toHaveBeenCalledWith(
diff --git a/packages/fxa-settings/src/pages/Signup/index.test.tsx b/packages/fxa-settings/src/pages/Signup/index.test.tsx
index 722d4170fbb..89b6f13d3d4 100644
--- a/packages/fxa-settings/src/pages/Signup/index.test.tsx
+++ b/packages/fxa-settings/src/pages/Signup/index.test.tsx
@@ -311,8 +311,10 @@ describe('Signup page', () => {
screen.queryByRole('button', { name: /Continue with Apple/ })
).toBeInTheDocument();
- screen.getByRole('heading', { name: 'Create a password' });
- screen.getByText('to continue');
+ screen.getByRole('heading', {
+ name: MOCK_CMS_INFO.SignupSetPasswordPage.headline,
+ });
+ screen.getByText(MOCK_CMS_INFO.SignupSetPasswordPage.description);
});
it('renders as expected when cms enabled and on mobile', async () => {
@@ -328,7 +330,9 @@ describe('Signup page', () => {
);
// Await to let react-hook-form's internal state updates settle.
- await screen.findByRole('heading', { name: 'Create a password' });
+ await screen.findByRole('heading', {
+ name: MOCK_CMS_INFO.SignupSetPasswordPage.headline,
+ });
expect(
screen.queryByAltText(MOCK_CMS_INFO.SignupSetPasswordPage.logoAltText)
diff --git a/packages/fxa-settings/src/pages/mocks.tsx b/packages/fxa-settings/src/pages/mocks.tsx
index 07bfdb7a2b6..eee763e88a9 100644
--- a/packages/fxa-settings/src/pages/mocks.tsx
+++ b/packages/fxa-settings/src/pages/mocks.tsx
@@ -106,15 +106,15 @@ export const MOCK_CMS_INFO = {
headerLogoUrl:
'https://cdn.accounts.firefox.com/other/firefox-browser-logo.svg',
logoAltText: 'logo',
- headerLogoAltText: 'custom-header-logo',
- pageTitle: 'MOCK Shared Title',
+ headerLogoAltText: 'CMS: custom-header-logo',
+ pageTitle: 'CMS: Shared Title',
featureFlags: {
syncConfirmedPageHideCTA: false,
syncHidePromoAfterLogin: false,
},
favicon: '',
additionalAccessibilityInfo:
- 'Firefox will try sending you back to use an email mask after you sign in.',
+ 'CMS: Firefox will try sending you back to use an email mask after you sign in.',
backgrounds: {
header: 'linear-gradient(135deg, #6B4DFB 0%, #3A1A78 100%)',
defaultLayout:
@@ -125,93 +125,93 @@ export const MOCK_CMS_INFO = {
EmailFirstPage: {
logoUrl: 'https://cdn.accounts.firefox.com/other/firefox-browser-logo.svg',
logoAltText: 'custom-email-first-logo',
- headline: 'Sign up or sign in to your Mozilla account',
+ headline: 'CMS: Sign up or sign in to your Mozilla account',
description:
- 'Stay protected with continuous data monitoring and automatic data removal.',
- primaryButtonText: 'Continue',
- pageTitle: 'Sign up or sign in to your Mozilla account',
+ 'Stay protected with continuous data monitoring and automatic data removal. (from cms)',
+ primaryButtonText: 'CMS: Continue',
+ pageTitle: 'CMS: Sign up or sign in to your Mozilla account',
},
SignupSetPasswordPage: {
logoUrl: 'https://cdn.accounts.firefox.com/other/firefox-browser-logo.svg',
logoAltText: 'custom-signup-logo',
- headline: 'Create a password',
- description: 'to continue',
- primaryButtonText: 'Continue',
- pageTitle: 'Create a password',
+ headline: 'CMS: Create a password',
+ description: 'CMS: to continue',
+ primaryButtonText: 'CMS: Continue',
+ pageTitle: 'CMS: Create a password',
},
SignupConfirmCodePage: {
- headline: 'Enter confirmation code',
- description: 'For your Mozilla account',
- primaryButtonText: 'Confirm',
- pageTitle: 'Enter confirmation code',
+ headline: 'CMS: Enter confirmation code',
+ description: 'CMS: For your Mozilla account',
+ primaryButtonText: 'CMS: Confirm',
+ pageTitle: 'CMS: Enter confirmation code',
},
SignupConfirmedSyncPage: {
- headline: 'Sync is turned on',
+ headline: 'CMS: Sync is turned on',
description:
- 'Your passwords, addresses, bookmarks, history, and more can sync everywhere you use Firefox.',
- primaryButtonText: 'Add another device',
- pageTitle: 'Sync is turned on',
+ 'CMS: Your passwords, addresses, bookmarks, history, and more can sync everywhere you use Firefox.',
+ primaryButtonText: 'CMS: Add another device',
+ pageTitle: 'CMS: Sync is turned on',
primaryImage: {
url: MOCK_CMS_PRIMARY_IMAGE_URL,
- altText: 'A cartoon fox with a laptop and a smartphone',
+ altText: 'CMS: A cartoon fox with a laptop and a smartphone',
},
},
PostVerifySetPasswordPage: {
- headline: 'Create a password to sync',
+ headline: 'CMS: Create a password to sync',
description:
- 'A Mozilla account works with sync to help protect your browsing, passwords, and more.',
- primaryButtonText: 'Continue',
- pageTitle: 'Create a password to sync',
+ 'CMS: A Mozilla account works with sync to help protect your browsing, passwords, and more.',
+ primaryButtonText: 'CMS: Continue',
+ pageTitle: 'CMS: Create a password to sync',
},
SigninPage: {
- headline: 'Enter your password',
- description: 'for your Mozilla account',
- primaryButtonText: 'Sign in',
- pageTitle: 'Enter your password',
+ headline: 'CMS: Enter your password',
+ description: 'CMS: for your Mozilla account',
+ primaryButtonText: 'CMS: Sign in',
+ pageTitle: 'CMS: Enter your password',
},
SigninTokenCodePage: {
- headline: 'Enter confirmation code',
- description: 'for your Mozilla account',
- primaryButtonText: 'Continue',
- pageTitle: 'Enter confirmation code',
+ headline: 'CMS: Enter confirmation code',
+ description: 'CMS: for your Mozilla account',
+ primaryButtonText: 'CMS: Continue',
+ pageTitle: 'CMS: Enter confirmation code',
},
SigninUnblockCodePage: {
- headline: 'Authorize this sign-in',
- description: 'for your Mozilla account',
- primaryButtonText: 'Continue',
- pageTitle: 'Authorize this sign-in',
+ headline: 'CMS: Authorize this sign-in',
+ description: 'CMS: for your Mozilla account',
+ primaryButtonText: 'CMS: Continue',
+ pageTitle: 'CMS: Authorize this sign-in',
},
SigninTotpCodePage: {
- headline: 'Verify your identity',
- description: 'Use your authenticator app to continue',
- primaryButtonText: 'Verify code',
- pageTitle: 'Two-step verification',
+ headline: 'CMS: Verify your identity',
+ description: 'CMS: Use your authenticator app to continue',
+ primaryButtonText: 'CMS: Verify code',
+ pageTitle: 'CMS: Two-step verification',
},
SigninRecoveryChoicePage: {
- headline: 'Choose your recovery',
- description: 'Select how you want to verify your identity',
- primaryButtonText: 'Continue recovery',
- pageTitle: 'Recovery method selection',
+ headline: 'CMS: Choose your recovery',
+ description: 'CMS: Select how you want to verify your identity',
+ primaryButtonText: 'CMS: Continue recovery',
+ pageTitle: 'CMS: Recovery method selection',
},
SigninRecoveryCodePage: {
- headline: 'Use a backup code',
- description: 'Enter one of your saved backup codes',
- primaryButtonText: 'Submit code',
- pageTitle: 'Backup code verification',
+ headline: 'CMS: Use a backup code',
+ description: 'CMS: Enter one of your saved backup codes',
+ primaryButtonText: 'CMS: Submit code',
+ pageTitle: 'CMS: Backup code verification',
primaryImage: {
url: MOCK_CMS_PRIMARY_IMAGE_URL,
- altText: 'A cartoon fox with a laptop and a smartphone',
+ altText: 'CMS: A cartoon fox with a laptop and a smartphone',
},
},
SigninRecoveryPhonePage: {
- headline: 'Check your phone',
- description: 'We sent a verification code to your phone',
- primaryButtonText: 'Verify phone code',
- pageTitle: 'Phone recovery verification',
+ headline: 'CMS: Check your phone',
+ description: 'CMS: We sent a verification code to your phone',
+ primaryButtonText: 'CMS: Verify phone code',
+ pageTitle: 'CMS: Phone recovery verification',
primaryImage: {
url: MOCK_CMS_PRIMARY_IMAGE_URL,
- altText: 'A cartoon fox with a laptop and a smartphone',
+ altText: 'CMS: A cartoon fox with a laptop and a smartphone',
},
},
};