Skip to content

Commit 39d6e65

Browse files
authored
Merge pull request #19529 from mozilla/FXA-12485
bug(settings): isInvalidJwtError not check when invoking confirmReplaceTotp
2 parents 647fe61 + d33ddd4 commit 39d6e65

3 files changed

Lines changed: 44 additions & 1 deletion

File tree

packages/fxa-settings/src/components/Settings/Page2faChange/index.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { MOCK_TOTP_INFO, Subject } from './mocks';
99
import userEvent from '@testing-library/user-event';
1010
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
1111
import GleanMetrics from '../../../lib/glean';
12+
import { JwtNotFoundError } from '../../../lib/cache';
1213

1314
const mockNavigate = jest.fn();
1415
jest.mock('../../../lib/hooks/useNavigateWithQuery', () => ({
@@ -34,6 +35,12 @@ jest.mock('../../../lib/glean', () => ({
3435
},
3536
}));
3637

38+
const mockErrorHandler = jest.fn();
39+
jest.mock('react-error-boundary', () => ({
40+
...jest.requireActual('react-error-boundary'),
41+
useErrorHandler: () => mockErrorHandler,
42+
}));
43+
3744
describe('Page2faChange', () => {
3845
it('renders as expected', async () => {
3946
renderWithLocalizationProvider(<Subject />);
@@ -144,4 +151,26 @@ describe('Page2faChange', () => {
144151
)
145152
).toBeInTheDocument();
146153
});
154+
155+
it('invokes the MFA errorHandler if the error is due to an expired jwt', async () => {
156+
const missingJwtError = new JwtNotFoundError();
157+
renderWithLocalizationProvider(
158+
<Subject
159+
account={{
160+
startReplaceTotp: jest.fn().mockResolvedValue(MOCK_TOTP_INFO),
161+
confirmReplaceTotp: jest.fn().mockRejectedValue(missingJwtError),
162+
}}
163+
/>
164+
);
165+
const codeInput = await screen.findByRole('textbox', {
166+
name: 'Enter 6-digit code',
167+
});
168+
const continueButton = await screen.findByRole('button', {
169+
name: 'Continue',
170+
});
171+
await userEvent.type(codeInput, '000000');
172+
await userEvent.click(continueButton);
173+
174+
expect(mockErrorHandler).toHaveBeenCalledWith(missingJwtError);
175+
});
147176
});

packages/fxa-settings/src/components/Settings/Page2faChange/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import VerifiedSessionGuard from '../VerifiedSessionGuard';
1818
import { GleanClickEventType2FA } from '../../../lib/types';
1919
import { FtlMsg } from 'fxa-react/lib/utils';
2020
import { MfaGuard } from '../MfaGuard';
21+
import { isInvalidJwtError } from '../../../lib/mfa-guard-utils';
22+
import { useErrorHandler } from 'react-error-boundary';
2123

2224
export const MfaGuardedPage2faChange = (_: RouteComponentProps) => {
2325
return (
@@ -37,6 +39,7 @@ export const Page2faChange = () => {
3739
loading: totpInfoLoading,
3840
error: totpInfoError,
3941
} = useTotpReplace();
42+
const errorHandler = useErrorHandler();
4043

4144
const localizedPageTitle = ftlMsgResolver.getMsg(
4245
'page-2fa-change-title',
@@ -103,6 +106,10 @@ export const Page2faChange = () => {
103106
try {
104107
await account.confirmReplaceTotp(code);
105108
} catch (error) {
109+
if (isInvalidJwtError(error)) {
110+
errorHandler(error);
111+
return { error: true };
112+
}
106113
return { error: true };
107114
}
108115

packages/fxa-settings/src/lib/hooks/useTotpReplace/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
import { useEffect, useState } from 'react';
6+
import { useErrorHandler } from 'react-error-boundary';
67
import { useAccount, useSession } from '../../../models';
78
import { TotpInfo } from '../../types';
9+
import { isInvalidJwtError } from '../../mfa-guard-utils';
810

911
export const useTotpReplace = () => {
1012
const account = useAccount();
1113
const session = useSession();
14+
const errorHandler = useErrorHandler();
1215

1316
const [totpInfo, setTotpInfo] = useState<TotpInfo | undefined>();
1417
const [loading, setLoading] = useState(true);
@@ -27,6 +30,10 @@ export const useTotpReplace = () => {
2730
const result = await account.startReplaceTotp();
2831
if (!cancelled) setTotpInfo(result);
2932
} catch (err) {
33+
if (isInvalidJwtError(err)) {
34+
errorHandler(err);
35+
return;
36+
}
3037
if (!cancelled) setError(err as Error);
3138
} finally {
3239
if (!cancelled) setLoading(false);
@@ -38,7 +45,7 @@ export const useTotpReplace = () => {
3845
return () => {
3946
cancelled = true;
4047
};
41-
}, [account, session.verified]);
48+
}, [account, session.verified, errorHandler]);
4249

4350
return {
4451
totpInfo,

0 commit comments

Comments
 (0)