Merge pull request #16392 from mozilla/FXA-9054

cleanup(settings): Remove confirm and confirm_signin in react
This commit is contained in:
Lauren Zugai 2024-02-12 16:15:42 -06:00 коммит произвёл GitHub
Родитель 5b301aa729 280947b876
Коммит a0a8fba744
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
14 изменённых файлов: 4 добавлений и 617 удалений

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

@ -105,6 +105,7 @@ const BaseAuthenticationBroker = Backbone.Model.extend({
afterResetPasswordConfirmationPoll: new NullBehavior(),
afterSignIn: new NavigateBehavior('signin_confirmed'),
afterSignInConfirmationPoll: new NavigateBehavior('signin_confirmed'),
// with React conversion, we are deprecating the confirm view in favor of 'confirm_signup_code'
afterSignUp: new NavigateBehavior('confirm'),
afterSignUpConfirmationPoll: new NavigateOrRedirectBehavior(
'signup_confirmed'

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

@ -172,6 +172,7 @@ export default {
const verificationMethod = account.get('verificationMethod');
const verificationReason = account.get('verificationReason');
// with React conversion, we are deprecating the confirm_signin view in favor of 'signin_token_code'
if (
(verificationReason === VerificationReasons.SIGN_IN &&
verificationMethod === VerificationMethods.EMAIL) ||
@ -221,7 +222,7 @@ export default {
this.navigate('confirm_signup_code', { account });
});
}
// with React conversion, we are deprecating the default confirm_signin view in favor of 'signin_token_code'
return this.navigate('confirm', { account });
}

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

@ -7,7 +7,7 @@ import { RouteComponentProps, Router, useLocation } from '@reach/router';
import { QueryParams } from '../..';
import { currentAccount, sessionToken } from '../../lib/cache';
import { currentAccount } from '../../lib/cache';
import { firefox } from '../../lib/channels/firefox';
import GleanMetrics from '../../lib/glean';
import * as Metrics from '../../lib/metrics';
@ -43,7 +43,6 @@ import Clear from '../../pages/Clear';
import CookiesDisabled from '../../pages/CookiesDisabled';
import CompleteResetPasswordContainer from '../../pages/ResetPassword/CompleteResetPassword/container';
import CompleteSigninContainer from '../../pages/Signin/CompleteSignin/container';
import Confirm from 'fxa-settings/src/pages/Signup/Confirm';
import ConfirmResetPassword from '../../pages/ResetPassword/ConfirmResetPassword';
import ConfirmSignupCodeContainer from '../../pages/Signup/ConfirmSignupCode/container';
import Legal from '../../pages/Legal';
@ -223,7 +222,6 @@ const AuthAndAccountSetupRoutes = ({
isSignedIn,
integration,
}: { isSignedIn: boolean; integration: Integration } & RouteComponentProps) => {
const sessionTokenId = sessionToken();
const localAccount = currentAccount();
// TODO: MozServices / string discrepancy, FXA-6802
const serviceName = integration.getServiceName() as MozServices;
@ -304,7 +302,6 @@ const AuthAndAccountSetupRoutes = ({
{/* Signup */}
<CannotCreateAccount path="/cannot_create_account/*" />
<Confirm path="/confirm/*" {...{ sessionTokenId }} />
<ConfirmSignupCodeContainer
path="/confirm_signup_code/*"
{...{ integration }}

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

@ -33,10 +33,6 @@ const ConfirmWithLink = ({
resendStatus,
errorMessage,
}: ConfirmWithLinkProps) => {
// (temporarily?) removed `Open With Webmail` functionality
// Not currently functional in content-server/prod so requires fix/new utility
// File follow-up to check with Product to see if we want to recreate this functionality
return (
<>
<CardHeader

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

@ -1,5 +0,0 @@
## ConfirmSignin component
confirm-signin-header = Confirm this sign-in
# { $email } is the email entered by the user and where the signin confirmation link was sent
confirm-signin-message = Check your email for the sign-in confirmation link sent to { $email }

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

@ -1,32 +0,0 @@
/* 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 ConfirmSignin, { ConfirmSigninProps } from '.';
import AppLayout from '../../../components/AppLayout';
import { LocationProvider } from '@reach/router';
import { Meta } from '@storybook/react';
import { MOCK_ACCOUNT } from '../../../models/mocks';
import { withLocalization } from 'fxa-react/lib/storybooks';
export default {
title: 'Pages/Signin/ConfirmSignin',
component: ConfirmSignin,
decorators: [withLocalization],
} as Meta;
const storyWithProps = (props: ConfirmSigninProps) => {
const story = () => (
<LocationProvider>
<AppLayout>
<ConfirmSignin {...props} />
</AppLayout>
</LocationProvider>
);
return story;
};
export const Default = storyWithProps({
email: MOCK_ACCOUNT.primaryEmail.email,
});

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

@ -1,61 +0,0 @@
/* 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, screen } from '@testing-library/react';
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider'; // import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils';
// import { FluentBundle } from '@fluent/bundle';
import { usePageViewEvent } from '../../../lib/metrics';
import ConfirmSignin, { viewName } from '.';
import { MOCK_ACCOUNT } from '../../../models/mocks';
import { REACT_ENTRYPOINT } from '../../../constants';
jest.mock('../../../lib/metrics', () => ({
usePageViewEvent: jest.fn(),
}));
describe('ConfirmSignin', () => {
// TODO: enable l10n tests when they've been updated to handle embedded tags in ftl strings
// TODO: in FXA-6461
// let bundle: FluentBundle;
// beforeAll(async () => {
// bundle = await getFtlBundle('settings');
// });
// TODO: add tests for all metrics as they are added
it("renders default view as expected with user's email", () => {
renderWithLocalizationProvider(
<ConfirmSignin email={MOCK_ACCOUNT.primaryEmail.email} />
);
// testAllL10n(screen, bundle);
const headingEl = screen.getByRole('heading', { level: 1 });
expect(headingEl).toHaveTextContent('Confirm this sign-in');
screen.getByText(
`Check your email for the sign-in confirmation link sent to ${MOCK_ACCOUNT.primaryEmail.email}`
);
screen.getByRole('button', { name: 'Not in inbox or spam folder? Resend' });
});
it('resends the email when the user clicks the resend button', () => {
renderWithLocalizationProvider(
<ConfirmSignin email={MOCK_ACCOUNT.primaryEmail.email} />
);
const headingEl = screen.getByRole('heading', { level: 1 });
expect(headingEl).toHaveTextContent('Confirm this sign-in');
const resendEmailButton = screen.getByRole('button', {
name: 'Not in inbox or spam folder? Resend',
});
fireEvent.click(resendEmailButton);
// TO-DO: Once we know where this functionality is coming from, we'll be able to test it.
// Add in a test to verify that it's called.
});
it('emits a metrics event on render', () => {
renderWithLocalizationProvider(
<ConfirmSignin email={MOCK_ACCOUNT.primaryEmail.email} />
);
expect(usePageViewEvent).toHaveBeenCalledWith(viewName, REACT_ENTRYPOINT);
});
});

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

@ -1,74 +0,0 @@
/* 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, { useState } from 'react';
import { logViewEvent, usePageViewEvent } from '../../../lib/metrics';
import { RouteComponentProps } from '@reach/router';
import ConfirmWithLink, {
ConfirmWithLinkPageStrings,
} from '../../../components/ConfirmWithLink';
import { REACT_ENTRYPOINT } from '../../../constants';
import { ResendStatus } from '../../../lib/types';
import { useFtlMsgResolver } from '../../../models';
import { getLocalizedErrorMessage } from '../../../lib/auth-errors/auth-errors';
export type ConfirmSigninProps = {
email: string;
goBackCallback?: () => void;
};
export const viewName = 'confirm-signin';
const ConfirmSignin = ({
email,
goBackCallback,
}: RouteComponentProps & ConfirmSigninProps) => {
usePageViewEvent(viewName, REACT_ENTRYPOINT);
const ftlMsgResolver = useFtlMsgResolver();
const [resendStatus, setResendStatus] = useState<ResendStatus>(
ResendStatus['not sent']
);
const [errorMessage, setErrorMessage] = useState<string>();
const confirmSigninPageText: ConfirmWithLinkPageStrings = {
headingFtlId: 'confirm-signin-heading',
headingText: 'Confirm this sign-in',
instructionFtlId: 'confirm-signin-instruction',
instructionText: `Check your email for the sign-in confirmation link sent to ${email}`,
};
const resendEmailHandler = async () => {
try {
// TO-DO: signin confirmation email to user.
logViewEvent(viewName, 'resend', REACT_ENTRYPOINT);
setErrorMessage('');
setResendStatus(ResendStatus['sent']);
} catch (err) {
const localizedErrorMessage = getLocalizedErrorMessage(
ftlMsgResolver,
err
);
setResendStatus(ResendStatus['error']);
setErrorMessage(localizedErrorMessage);
}
};
return (
<>
<ConfirmWithLink
{...{
email,
resendEmailHandler,
resendStatus,
errorMessage,
}}
confirmWithLinkPageStrings={confirmSigninPageText}
/>
</>
);
};
export default ConfirmSignin;

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

@ -1,4 +0,0 @@
export const EXAMPLE_EMAIL = 'example@domain.com';
export const mockGoBackCallback = () => {
console.log('Navigating back!');
};

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

@ -1,7 +0,0 @@
## Confirm page
## Users will see this page if a verification link was sent to their email address
## when setting up a new account
confirm-signup-heading = Confirm your account
# { $email } is the email entered by the user and where the signup confirmation link was sent
confirm-signup-instruction = Check your email for the confirmation link sent to { $email }

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

@ -1,44 +0,0 @@
/* 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 Confirm from '.';
import { LocationProvider } from '@reach/router';
import { Meta } from '@storybook/react';
import { mockAppContext } from '../../../models/mocks';
import { withLocalization } from 'fxa-react/lib/storybooks';
import { Account, AppContext } from 'fxa-settings/src/models';
import {
MOCK_PROFILE_WITH_RESEND_ERROR,
MOCK_PROFILE_WITH_RESEND_SUCCESS,
MOCK_SESSION_TOKEN,
MOCK_UNVERIFIED_SESSION,
} from './mocks';
export default {
title: 'Pages/Signup/Confirm',
component: Confirm,
decorators: [withLocalization],
} as Meta;
const storyWithContext = (account: Account) => {
const story = () => (
<LocationProvider>
<AppContext.Provider
value={mockAppContext({ account, session: MOCK_UNVERIFIED_SESSION })}
>
<Confirm sessionTokenId={MOCK_SESSION_TOKEN} />
</AppContext.Provider>
</LocationProvider>
);
return story;
};
export const WithSuccessOnResend = storyWithContext(
MOCK_PROFILE_WITH_RESEND_SUCCESS
);
export const WithErrorOnResend = storyWithContext(
MOCK_PROFILE_WITH_RESEND_ERROR
);

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

@ -1,147 +0,0 @@
/* 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, screen, waitFor } from '@testing-library/react';
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
import { LocationProvider } from '@reach/router';
// import { FluentBundle } from '@fluent/bundle';
// import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils';
import { FIREFOX_NOREPLY_EMAIL, REACT_ENTRYPOINT } from '../../../constants';
import { usePageViewEvent } from '../../../lib/metrics';
import { Account, AppContext, Session } from '../../../models';
import {
mockAppContext,
mockEmail,
MOCK_ACCOUNT,
MOCK_PROFILE_INFO,
mockSession,
} from '../../../models/mocks';
import Confirm, { viewName } from '.';
import { MOCK_SESSION_TOKEN, MOCK_UNVERIFIED_SESSION } from './mocks';
jest.mock('../../../lib/metrics', () => ({
usePageViewEvent: jest.fn(),
logViewEvent: jest.fn(),
}));
jest.mock('@reach/router', () => ({
...jest.requireActual('@reach/router'),
navigate: jest.fn(),
}));
const MOCK_ACCOUNT_WITH_SUCCESS = {
getProfileInfo: jest.fn().mockResolvedValue(MOCK_PROFILE_INFO),
sendVerificationCode: jest.fn().mockResolvedValue(true),
primaryEmail: mockEmail(MOCK_ACCOUNT.primaryEmail.email, true, false),
} as unknown as Account;
const MOCK_ACCOUNT_WITH_ERROR = {
getProfileInfo: jest.fn().mockResolvedValue(MOCK_PROFILE_INFO),
sendVerificationCode: jest.fn().mockRejectedValue(Error),
primaryEmail: mockEmail(MOCK_ACCOUNT.primaryEmail.email, true, false),
} as unknown as Account;
function renderWithContext(
account: Account | undefined,
session: Session,
sessionTokenId: string | null
) {
renderWithLocalizationProvider(
<AppContext.Provider
value={mockAppContext({
account,
session,
})}
>
<LocationProvider>
<Confirm {...{ sessionTokenId }} />
</LocationProvider>
</AppContext.Provider>
);
}
describe('Confirm page', () => {
// TODO : l10n test currently failing on image l10n
// - enabling these tests will require attributes handling
// let bundle: FluentBundle;
// beforeAll(async () => {
// bundle = await getFtlBundle('settings');
// });
afterEach(() => jest.clearAllMocks());
it('renders a loading spinner until account data is available', async () => {
renderWithContext(
MOCK_ACCOUNT_WITH_SUCCESS,
MOCK_UNVERIFIED_SESSION,
MOCK_SESSION_TOKEN
);
expect(screen.getByRole('img', { name: 'Loading…' })).toBeInTheDocument();
await waitFor(() => {
const headingEl = screen.getByRole('heading', { level: 1 });
expect(headingEl).toHaveTextContent('Confirm your account');
});
});
it('renders as expected with unverified session, session token and profile info', async () => {
renderWithContext(
MOCK_ACCOUNT_WITH_SUCCESS,
MOCK_UNVERIFIED_SESSION,
MOCK_SESSION_TOKEN
);
// wait for setEmail to update with email from account model
await waitFor(() => {
const headingEl = screen.getByRole('heading', { level: 1 });
expect(headingEl).toHaveTextContent('Confirm your account');
screen.getByText(
`Check your email for the confirmation link sent to ${MOCK_ACCOUNT.primaryEmail.email}`
);
screen.getByRole('button', {
name: 'Not in inbox or spam folder? Resend',
});
// testAllL10n(screen, bundle, { email: MOCK_ACCOUNT.primaryEmail.email });
});
});
it('resends the email when the user clicks the resend button', async () => {
const account: Account = MOCK_ACCOUNT_WITH_SUCCESS;
const session = mockSession(false, false);
renderWithContext(account, session, MOCK_SESSION_TOKEN);
await waitFor(() => {
const resendEmailButton = screen.getByRole('button', {
name: 'Not in inbox or spam folder? Resend',
});
fireEvent.click(resendEmailButton);
expect(session.sendVerificationCode).toBeCalled();
const successBannerText = `Email resent. Add ${FIREFOX_NOREPLY_EMAIL} to your contacts to ensure a smooth delivery.`;
expect(screen.getByText(successBannerText)).toBeInTheDocument();
});
});
it('renders an error banner when resending an email fails', async () => {
const account: Account = MOCK_ACCOUNT_WITH_ERROR;
const session = mockSession(false, true);
renderWithContext(account, session, MOCK_SESSION_TOKEN);
await waitFor(() => {
const resendEmailButton = screen.getByRole('button', {
name: 'Not in inbox or spam folder? Resend',
});
fireEvent.click(resendEmailButton);
expect(session.sendVerificationCode).toBeCalled();
const bannerText = `Unexpected error`;
expect(screen.getByText(bannerText)).toBeInTheDocument();
});
});
// only page view event added, could not hit route on prod to test which other metrics should be emitted
it('emits a metrics event on render', async () => {
renderWithContext(
MOCK_ACCOUNT_WITH_SUCCESS,
MOCK_UNVERIFIED_SESSION,
MOCK_SESSION_TOKEN
);
await waitFor(() => {
expect(usePageViewEvent).toHaveBeenCalledWith(viewName, REACT_ENTRYPOINT);
});
});
});

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

@ -1,206 +0,0 @@
/* 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, { useCallback, useEffect, useState } from 'react';
import {
logErrorEvent,
logViewEvent,
usePageViewEvent,
} from '../../../lib/metrics';
import { RouteComponentProps, useNavigate } from '@reach/router';
import ConfirmWithLink, {
ConfirmWithLinkPageStrings,
} from '../../../components/ConfirmWithLink';
import {
NAVIGATION_TIMEOUT_MS,
POLLING_INTERVAL_MS,
REACT_ENTRYPOINT,
} from '../../../constants';
import { ResendStatus } from '../../../lib/types';
import AppLayout from 'fxa-settings/src/components/AppLayout';
import {
useAccount,
useFtlMsgResolver,
useInterval,
useSession,
} from 'fxa-settings/src/models';
import {
AuthUiErrors,
getLocalizedErrorMessage,
} from 'fxa-settings/src/lib/auth-errors/auth-errors';
import LoadingSpinner from 'fxa-react/components/LoadingSpinner';
import { hardNavigateToContentServer } from 'fxa-react/lib/utils';
// This page is no longer part of the typical/expected signup flow, but has been preserverd during
// the conversion from backbone to react as we were still seeing some traffic to this route.
// TODO in FXA-7185: Check metrics once this React page is rolled out to determine if this page can be entirely replaced by ConfirmSignupCode.
export const viewName = 'confirm';
export type ConfirmProps = {
sessionTokenId?: string | null;
};
export const Confirm = ({
sessionTokenId,
}: ConfirmProps & RouteComponentProps) => {
usePageViewEvent(viewName, REACT_ENTRYPOINT);
const ftlMsgResolver = useFtlMsgResolver();
// Show a loading spinner until all checks complete. Without this,
// users without a session will experience some jank due to an
// immediate redirect or rerender of this page.
const [showLoadingSpinner, setShowLoadingSpinner] = useState(true);
const [resendStatus, setResendStatus] = useState<ResendStatus>(
ResendStatus['not sent']
);
const [errorMessage, setErrorMessage] = useState<string>();
const [email, setEmail] = useState('');
const account = useAccount();
const session = useSession();
const navigate = useNavigate();
const [isPolling, setIsPolling] = useState<number | null>(
POLLING_INTERVAL_MS
);
const getEmail = useCallback(async () => {
const response = await account.getProfileInfo();
setEmail(response.primaryEmail.email);
}, [account]);
const redirectToSignup = useCallback(() => {
hardNavigateToContentServer('/signup');
}, []);
const confirmSignupPageText: ConfirmWithLinkPageStrings = {
headingFtlId: 'confirm-signup-heading',
headingText: 'Confirm your account',
instructionFtlId: 'confirm-signup-instruction',
instructionText: `Check your email for the confirmation link sent to ${email}`,
};
// Verifies if we have access to profile info and session token.
// If we do, set the email and render the page. If not, we don't know
// who the user is and can't confirm if we've sent a confirmation
// link, and we can't send a new one without an email address => redirect
// the user to retry signup.
useEffect(() => {
try {
if (sessionTokenId) {
getEmail();
} else {
redirectToSignup();
}
} catch (e) {
redirectToSignup();
}
}, [getEmail, redirectToSignup, sessionTokenId]);
useEffect(() => {
if (email) {
setShowLoadingSpinner(false);
}
}, [email, setShowLoadingSpinner]);
const navigateToConfirmCode = useCallback(
() =>
navigate('/confirm_signup_code?showReactApp=true', {
state: { email },
replace: true,
}),
[email, navigate]
);
// TODO implement broker to determine the the next screen
const navigateToNextScreen = () => {
logViewEvent(viewName, 'verification.success');
// TODO check if isForcePasswordChange
// navigate('/post_verify/password/force_password_change', {account})
// default behaviour: '/signup_confirmed'
// if Sync: '/connect_another_device'
// if Web: '/settings'
navigate('/settings', { replace: true });
};
// Adds a timeout before navigating to the /confirm_signup_code page
// when the user clicks on the resend email link.
useEffect(() => {
function onTimeout() {
navigateToConfirmCode();
}
let navigateTimeoutId: NodeJS.Timeout;
if (resendStatus === ResendStatus.sent) {
navigateTimeoutId = setTimeout(onTimeout, NAVIGATION_TIMEOUT_MS);
}
return () => {
clearTimeout(navigateTimeoutId);
};
}, [navigateToConfirmCode, resendStatus]);
// Subscribe to account updates to find out if the session becomes verified.
// Stay on this page until the session is verified, then automatically
// navigate to the next screen.
useInterval(async () => {
try {
const sessionVerified = await session.isSessionVerified();
if (sessionVerified) {
navigateToNextScreen();
setIsPolling(null);
}
} catch (e) {
setIsPolling(null);
}
}, isPolling);
const resendEmailHandler = async () => {
try {
// The logic here differs from content-server. Since we are moving away
// from confirmation link, this resend function sends a verification code
// instead of a verification link and navigates to /signup_confirm_code.
// This avoids adding a (to be discontinued) method to the React Account model.
await session.sendVerificationCode();
setResendStatus(ResendStatus.sent);
} catch (err) {
const localizedErrorMessage = getLocalizedErrorMessage(
ftlMsgResolver,
err
);
setResendStatus(ResendStatus['error']);
setErrorMessage(localizedErrorMessage);
if (AuthUiErrors['INVALID_TOKEN'].errno === err.errno) {
logErrorEvent({ viewName, ...err });
// TODO: When redirectToSignup is changed to use navigate,
// pass in the error so it can be displayed in an banner
// on the /signup page
redirectToSignup();
}
return;
}
setResendStatus(ResendStatus['sent']);
};
if (showLoadingSpinner) {
return <LoadingSpinner fullScreen />;
}
return (
<AppLayout>
<ConfirmWithLink
confirmWithLinkPageStrings={confirmSignupPageText}
{...{
email,
resendEmailHandler,
resendStatus,
errorMessage,
}}
/>
</AppLayout>
);
};
export default Confirm;

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

@ -1,28 +0,0 @@
/* 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 { Account } from 'fxa-settings/src/models';
import {
mockEmail,
mockSession,
MOCK_PROFILE_INFO,
} from 'fxa-settings/src/models/mocks';
export const MOCK_PROFILE_WITH_RESEND_SUCCESS = {
getProfileInfo: () => Promise.resolve(MOCK_PROFILE_INFO),
sendVerificationCode: () => Promise.resolve({}),
primaryEmail: mockEmail('blabidi@blabidiboop.com', true, false),
} as unknown as Account;
export const MOCK_PROFILE_WITH_RESEND_ERROR = {
getProfileInfo: () => Promise.resolve(MOCK_PROFILE_INFO),
sendVerificationCode: () => Promise.reject(Error),
primaryEmail: mockEmail('blabidi@blabidiboop.com', true, false),
} as unknown as Account;
export const MOCK_UNVERIFIED_SESSION = mockSession(false);
export const MOCK_VERIFIED_SESSION = mockSession(true);
export const MOCK_SESSION_TOKEN = 'abc123';