Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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();

Expand All @@ -30,7 +43,13 @@ describe('ModalVerifySession', () => {
const onDismiss = jest.fn();
const onError = jest.fn();
renderWithRouter(
<AppContext.Provider value={{ account, session }}>
<AppContext.Provider
value={{
authClient,
account,
session,
}}
>
<ModalVerifySession {...{ onDismiss, onError }} />
</AppContext.Provider>
);
Expand All @@ -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(
<AppContext.Provider value={{ account, session }}>
<AppContext.Provider value={{ account, session, authClient }}>
<ModalVerifySession {...{ onDismiss, onError }} />
</AppContext.Provider>
);
Expand All @@ -67,7 +97,7 @@ describe('ModalVerifySession', () => {
const onDismiss = jest.fn();
const onError = jest.fn();
renderWithRouter(
<AppContext.Provider value={{ account, session }}>
<AppContext.Provider value={{ account, session, authClient }}>
<ModalVerifySession {...{ onDismiss, onError }} />
</AppContext.Provider>
);
Expand All @@ -88,7 +118,7 @@ describe('ModalVerifySession', () => {
const onDismiss = jest.fn();
const onError = jest.fn();
renderWithRouter(
<AppContext.Provider value={{ account, session }}>
<AppContext.Provider value={{ account, session, authClient }}>
<ModalVerifySession {...{ onDismiss, onError }} />
</AppContext.Provider>
);
Expand Down Expand Up @@ -122,7 +152,7 @@ describe('ModalVerifySession', () => {
const onDismiss = jest.fn();
const onError = jest.fn();
renderWithRouter(
<AppContext.Provider value={{ account, session }}>
<AppContext.Provider value={{ account, session, authClient }}>
<ModalVerifySession {...{ onDismiss, onError }} />
</AppContext.Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -28,6 +28,7 @@ export const ModalVerifySession = ({
onCompleted,
}: ModalProps) => {
const session = useSession();
const authClient = useAuthClient();
const [errorText, setErrorText] = useState<string>();
const hasSentVerificationCode = useRef(false);
const account = useAccount();
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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(
<AppContext.Provider
value={mockAppContext({ account, session: mockSession(true, false) })}
value={mockAppContext({
account,
session: mockSession(true, false),
authClient: {
sessionStatus: () => {
return {
details: {
sessionVerified: true,
},
};
},
} as unknown as AuthClient,
})}
>
<VerifiedSessionGuard {...{ onDismiss, onError }}>
<div data-testid="children">Content</div>
</VerifiedSessionGuard>
</AppContext.Provider>
)
<VerifiedSessionGuard {...{ onDismiss, onError }}>
<div data-testid="children">Content</div>
</VerifiedSessionGuard>
</AppContext.Provider>
)
);

expect(screen.getByTestId('children')).toBeInTheDocument();
Expand All @@ -46,14 +60,18 @@ it('renders the guard when unverified', async () => {
},
} as unknown as Account;

await act(async () => await renderWithRouter(
<AppContext.Provider value={mockAppContext({ account, session: mockSession(false) })}>
<VerifiedSessionGuard {...{ onDismiss, onError }}>
<div>Content</div>
</VerifiedSessionGuard>
</AppContext.Provider>
await act(
async () =>
await renderWithRouter(
<AppContext.Provider
value={mockAppContext({ account, session: mockSession(false) })}
>
<VerifiedSessionGuard {...{ onDismiss, onError }}>
<div>Content</div>
</VerifiedSessionGuard>
</AppContext.Provider>
)
);
);

expect(screen.getByTestId('modal-verify-session')).toBeInTheDocument();
});
19 changes: 19 additions & 0 deletions packages/fxa-settings/src/models/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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',
Expand Down