diff --git a/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.test.tsx b/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.test.tsx index fb4f17108f4..6b2daffcd0f 100644 --- a/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.test.tsx +++ b/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.test.tsx @@ -6,7 +6,11 @@ import 'mutationobserver-shim'; import React from 'react'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { mockSession, renderWithRouter } from '../../../models/mocks'; +import { + mockAuthClient, + mockSession, + renderWithRouter, +} from '../../../models/mocks'; import { Account, AppContext, Session } from '../../../models'; import { ModalVerifySession } from '.'; import { AuthUiErrors } from 'fxa-settings/src/lib/auth-errors/auth-errors'; @@ -18,6 +22,15 @@ const account = { } as unknown as Account; const session = mockSession(false); +const authClient = mockAuthClient(); + +// jest.mock('../../../models', () => ({ +// ...jest.requireActual('../../../models'), +// useAuthClient: () => { +// const authClient = mockAuthClient(); +// return authClient; +// }, +// })); window.console.error = jest.fn(); @@ -30,7 +43,13 @@ describe('ModalVerifySession', () => { const onDismiss = jest.fn(); const onError = jest.fn(); renderWithRouter( - + ); @@ -51,8 +70,19 @@ describe('ModalVerifySession', () => { it('sends verification code on mount', async () => { const onDismiss = jest.fn(); const onError = jest.fn(); + authClient.sessionStatus = jest.fn().mockReturnValue({ + state: 'unverified', + details: { + verified: false, + accountEmailVerified: true, + sessionVerified: false, + sessionVerificationMeetsMinimumAAL: false, + sessionVerificationMethod: 'email', + }, + }); + renderWithRouter( - + ); @@ -67,7 +97,7 @@ describe('ModalVerifySession', () => { const onDismiss = jest.fn(); const onError = jest.fn(); renderWithRouter( - + ); @@ -88,7 +118,7 @@ describe('ModalVerifySession', () => { const onDismiss = jest.fn(); const onError = jest.fn(); renderWithRouter( - + ); @@ -122,7 +152,7 @@ describe('ModalVerifySession', () => { const onDismiss = jest.fn(); const onError = jest.fn(); renderWithRouter( - + ); diff --git a/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.tsx b/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.tsx index a1fb8b8027d..47b5b141745 100644 --- a/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.tsx +++ b/packages/fxa-settings/src/components/Settings/ModalVerifySession/index.tsx @@ -7,7 +7,7 @@ import { useForm } from 'react-hook-form'; import Modal from '../Modal'; import InputText from '../../InputText'; import { ApolloError } from '@apollo/client'; -import { useAccount, useSession } from '../../../models'; +import { useAccount, useAuthClient, useSession } from '../../../models'; import { Localized, useLocalization } from '@fluent/react'; import { AuthUiErrors } from 'fxa-settings/src/lib/auth-errors/auth-errors'; import { getErrorFtlId } from '../../../lib/error-utils'; @@ -28,6 +28,7 @@ export const ModalVerifySession = ({ onCompleted, }: ModalProps) => { const session = useSession(); + const authClient = useAuthClient(); const [errorText, setErrorText] = useState(); const hasSentVerificationCode = useRef(false); const account = useAccount(); @@ -64,17 +65,21 @@ export const ModalVerifySession = ({ useEffect(() => { const getStatus = async () => { - // Check cache first, then do network request for session verification - if (session.verified) { + // Don't trust the cache for now, make an actual call. + const status = await authClient.sessionStatus(session.token); + if (status.details.sessionVerified) { onCompleted && onCompleted(); - } else if (!hasSentVerificationCode.current) { + return; + } + + if (!hasSentVerificationCode.current) { hasSentVerificationCode.current = true; await session.sendVerificationCode(); } }; getStatus(); - }, [session, onCompleted]); + }, [session, onCompleted, authClient]); // Destructure formState in advance to avoid logical operator short-circuiting // causing the isValid field to be conditionally subscribed. diff --git a/packages/fxa-settings/src/components/Settings/VerifiedSessionGuard/index.test.tsx b/packages/fxa-settings/src/components/Settings/VerifiedSessionGuard/index.test.tsx index 4685622ae58..20bebfad34a 100644 --- a/packages/fxa-settings/src/components/Settings/VerifiedSessionGuard/index.test.tsx +++ b/packages/fxa-settings/src/components/Settings/VerifiedSessionGuard/index.test.tsx @@ -12,6 +12,7 @@ import { } from '../../../models/mocks'; import { Account, AppContext } from '../../../models'; import { VerifiedSessionGuard } from '.'; +import AuthClient from 'fxa-auth-client/browser'; it('renders the content when verified', async () => { const account = { @@ -22,16 +23,29 @@ it('renders the content when verified', async () => { const onDismiss = jest.fn(); const onError = jest.fn(); - await act(async () => + await act( + async () => await renderWithRouter( { + return { + details: { + sessionVerified: true, + }, + }; + }, + } as unknown as AuthClient, + })} > - -
Content
-
-
- ) + +
Content
+
+
+ ) ); expect(screen.getByTestId('children')).toBeInTheDocument(); @@ -46,14 +60,18 @@ it('renders the guard when unverified', async () => { }, } as unknown as Account; - await act(async () => await renderWithRouter( - - -
Content
-
-
+ await act( + async () => + await renderWithRouter( + + +
Content
+
+
) - ); + ); expect(screen.getByTestId('modal-verify-session')).toBeInTheDocument(); }); diff --git a/packages/fxa-settings/src/models/mocks.tsx b/packages/fxa-settings/src/models/mocks.tsx index 8c3d9bbf5b2..2ead0bb68b0 100644 --- a/packages/fxa-settings/src/models/mocks.tsx +++ b/packages/fxa-settings/src/models/mocks.tsx @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import React from 'react'; +import AuthClient from 'fxa-auth-client/browser'; import { AccountData, ProfileInfo, Session } from '.'; import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider'; import { @@ -122,6 +123,23 @@ export function mockSession( return session; } +export function mockAuthClient() { + // There are plenty more methods to mock here, but this is these are the ones + // that get commonly used. + return { + sessionStatus: jest.fn().mockReturnValue({ + state: 'verified', + details: { + verified: true, + accountEmailVerified: true, + sessionVerified: true, + sessionVerificationMeetsMinimumAAL: true, + sessionVerificationMethod: 'email', + }, + }), + } as unknown as AuthClient; +} + export function mockSensitiveDataClient() { return new SensitiveDataClient(); } @@ -186,6 +204,7 @@ export function mockAppContext(context?: AppContextValue) { { account: MOCK_ACCOUNT, session: mockSession(), + authClient: mockAuthClient(), config: getDefault(), sensitiveDataClient: mockSensitiveDataClient(), uniqueUserId: '4a9512ac-3110-43df-aa8a-958A3d210b9c3',