@digitaldefiance/express-suite-react-components 5.0.2 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -4
- package/src/auth/AdminRoute.d.ts +8 -0
- package/src/auth/AdminRoute.d.ts.map +1 -0
- package/src/auth/AdminRoute.js +28 -0
- package/src/auth/Private.d.ts +6 -0
- package/src/auth/Private.d.ts.map +1 -0
- package/src/auth/Private.js +14 -0
- package/src/auth/PrivateRoute.d.ts +8 -0
- package/src/auth/PrivateRoute.d.ts.map +1 -0
- package/src/auth/PrivateRoute.js +23 -0
- package/src/auth/UnAuth.d.ts +6 -0
- package/src/auth/UnAuth.d.ts.map +1 -0
- package/src/auth/UnAuth.js +14 -0
- package/src/auth/UnAuthRoute.d.ts +8 -0
- package/src/auth/UnAuthRoute.d.ts.map +1 -0
- package/src/auth/UnAuthRoute.js +22 -0
- package/src/auth/{index.ts → index.d.ts} +3 -2
- package/src/auth/index.d.ts.map +1 -0
- package/src/auth/index.js +12 -0
- package/src/components/ApiAccess.d.ts +16 -0
- package/src/components/ApiAccess.d.ts.map +1 -0
- package/src/components/ApiAccess.js +77 -0
- package/src/components/BackupCodeLoginForm.d.ts +43 -0
- package/src/components/BackupCodeLoginForm.d.ts.map +1 -0
- package/src/components/BackupCodeLoginForm.js +139 -0
- package/src/components/BackupCodesForm.d.ts +26 -0
- package/src/components/BackupCodesForm.d.ts.map +1 -0
- package/src/components/BackupCodesForm.js +120 -0
- package/src/components/CategoryMenu.d.ts +17 -0
- package/src/components/CategoryMenu.d.ts.map +1 -0
- package/src/components/CategoryMenu.js +65 -0
- package/src/components/ChangePasswordForm.d.ts +26 -0
- package/src/components/ChangePasswordForm.d.ts.map +1 -0
- package/src/components/ChangePasswordForm.js +78 -0
- package/src/components/ConfirmationDialog.d.ts +13 -0
- package/src/components/ConfirmationDialog.d.ts.map +1 -0
- package/src/components/ConfirmationDialog.js +10 -0
- package/src/components/CurrencyCodeSelector.d.ts +9 -0
- package/src/components/CurrencyCodeSelector.d.ts.map +1 -0
- package/src/components/CurrencyCodeSelector.js +31 -0
- package/src/components/CurrencyInput.d.ts +13 -0
- package/src/components/CurrencyInput.d.ts.map +1 -0
- package/src/components/CurrencyInput.js +22 -0
- package/src/components/DashboardPage.d.ts +8 -0
- package/src/components/DashboardPage.d.ts.map +1 -0
- package/src/components/DashboardPage.js +10 -0
- package/src/components/DropdownMenu.d.ts +13 -0
- package/src/components/DropdownMenu.d.ts.map +1 -0
- package/src/components/DropdownMenu.js +63 -0
- package/src/components/ExpirationSecondsSelector.d.ts +13 -0
- package/src/components/ExpirationSecondsSelector.d.ts.map +1 -0
- package/src/components/ExpirationSecondsSelector.js +32 -0
- package/src/components/FakeEmailAdminPanel.d.ts +23 -0
- package/src/components/FakeEmailAdminPanel.d.ts.map +1 -0
- package/src/components/FakeEmailAdminPanel.js +147 -0
- package/src/components/Flag.d.ts +20 -0
- package/src/components/Flag.d.ts.map +1 -0
- package/src/components/Flag.js +43 -0
- package/src/components/ForgotPasswordForm.d.ts +18 -0
- package/src/components/ForgotPasswordForm.d.ts.map +1 -0
- package/src/components/ForgotPasswordForm.js +61 -0
- package/src/components/LoginForm.d.ts +44 -0
- package/src/components/LoginForm.d.ts.map +1 -0
- package/src/components/LoginForm.js +123 -0
- package/src/components/LogoutPage.d.ts +8 -0
- package/src/components/LogoutPage.d.ts.map +1 -0
- package/src/components/LogoutPage.js +16 -0
- package/src/components/RegisterForm.d.ts +100 -0
- package/src/components/RegisterForm.d.ts.map +1 -0
- package/src/components/RegisterForm.js +306 -0
- package/src/components/ResetPasswordForm.d.ts +23 -0
- package/src/components/ResetPasswordForm.d.ts.map +1 -0
- package/src/components/ResetPasswordForm.js +78 -0
- package/src/components/SideMenu.d.ts +8 -0
- package/src/components/SideMenu.d.ts.map +1 -0
- package/src/components/SideMenu.js +25 -0
- package/src/components/SideMenuListItem.d.ts +13 -0
- package/src/components/SideMenuListItem.d.ts.map +1 -0
- package/src/components/SideMenuListItem.js +44 -0
- package/src/components/T.d.ts +7 -0
- package/src/components/T.d.ts.map +1 -0
- package/src/components/T.js +13 -0
- package/src/components/TDiv.d.ts +9 -0
- package/src/components/TDiv.d.ts.map +1 -0
- package/src/components/TDiv.js +14 -0
- package/src/components/TImgAlt.d.ts +10 -0
- package/src/components/TImgAlt.d.ts.map +1 -0
- package/src/components/TImgAlt.js +14 -0
- package/src/components/TopMenu.d.ts +50 -0
- package/src/components/TopMenu.d.ts.map +1 -0
- package/src/components/TopMenu.js +79 -0
- package/src/components/TotpSetupForm.d.ts +24 -0
- package/src/components/TotpSetupForm.d.ts.map +1 -0
- package/src/components/TotpSetupForm.js +82 -0
- package/src/components/TotpVerificationForm.d.ts +23 -0
- package/src/components/TotpVerificationForm.d.ts.map +1 -0
- package/src/components/TotpVerificationForm.js +66 -0
- package/src/components/TranslatedTitle.d.ts +8 -0
- package/src/components/TranslatedTitle.d.ts.map +1 -0
- package/src/components/TranslatedTitle.js +15 -0
- package/src/components/UserLanguageSelector.d.ts +4 -0
- package/src/components/UserLanguageSelector.d.ts.map +1 -0
- package/src/components/UserLanguageSelector.js +31 -0
- package/src/components/UserMenu.d.ts +4 -0
- package/src/components/UserMenu.d.ts.map +1 -0
- package/src/components/UserMenu.js +12 -0
- package/src/components/UserSettingsForm.d.ts +113 -0
- package/src/components/UserSettingsForm.d.ts.map +1 -0
- package/src/components/UserSettingsForm.js +269 -0
- package/src/components/VerifyEmailPage.d.ts +24 -0
- package/src/components/VerifyEmailPage.d.ts.map +1 -0
- package/src/components/VerifyEmailPage.js +81 -0
- package/src/components/{index.ts → index.d.ts} +1 -1
- package/src/components/index.d.ts.map +1 -0
- package/src/components/index.js +35 -0
- package/src/contexts/AuthProvider.d.ts +186 -0
- package/src/contexts/AuthProvider.d.ts.map +1 -0
- package/src/contexts/AuthProvider.js +515 -0
- package/src/contexts/I18nProvider.d.ts +27 -0
- package/src/contexts/I18nProvider.d.ts.map +1 -0
- package/src/contexts/I18nProvider.js +60 -0
- package/src/contexts/MenuContext.d.ts +28 -0
- package/src/contexts/MenuContext.d.ts.map +1 -0
- package/src/contexts/MenuContext.js +292 -0
- package/src/contexts/SuiteConfigProvider.d.ts +44 -0
- package/src/contexts/SuiteConfigProvider.d.ts.map +1 -0
- package/src/contexts/SuiteConfigProvider.js +43 -0
- package/src/contexts/ThemeProvider.d.ts +15 -0
- package/src/contexts/ThemeProvider.d.ts.map +1 -0
- package/src/contexts/ThemeProvider.js +36 -0
- package/src/contexts/{index.ts → index.d.ts} +1 -0
- package/src/contexts/index.d.ts.map +1 -0
- package/src/contexts/index.js +8 -0
- package/src/hooks/{index.ts → index.d.ts} +1 -0
- package/src/hooks/index.d.ts.map +1 -0
- package/src/hooks/index.js +9 -0
- package/src/hooks/useAuthenticatedApi.d.ts +34 -0
- package/src/hooks/useAuthenticatedApi.d.ts.map +1 -0
- package/src/hooks/useAuthenticatedApi.js +46 -0
- package/src/hooks/useBackupCodes.d.ts +15 -0
- package/src/hooks/useBackupCodes.d.ts.map +1 -0
- package/src/hooks/useBackupCodes.js +74 -0
- package/src/hooks/useEmailVerification.d.ts +10 -0
- package/src/hooks/useEmailVerification.d.ts.map +1 -0
- package/src/hooks/useEmailVerification.js +40 -0
- package/src/hooks/useExpiringValue.d.ts +14 -0
- package/src/hooks/useExpiringValue.d.ts.map +1 -0
- package/src/hooks/useExpiringValue.js +53 -0
- package/src/hooks/useLocalStorage.d.ts +2 -0
- package/src/hooks/useLocalStorage.d.ts.map +1 -0
- package/src/hooks/useLocalStorage.js +15 -0
- package/src/hooks/useUserSettings.d.ts +48 -0
- package/src/hooks/useUserSettings.d.ts.map +1 -0
- package/src/hooks/useUserSettings.js +171 -0
- package/src/{index.ts → index.d.ts} +1 -1
- package/src/index.d.ts.map +1 -0
- package/src/index.js +12 -0
- package/src/interfaces/IAppConfig.d.ts +8 -0
- package/src/interfaces/IAppConfig.d.ts.map +1 -0
- package/src/interfaces/IAppConfig.js +2 -0
- package/src/interfaces/ICategoryConfig.d.ts +41 -0
- package/src/interfaces/ICategoryConfig.d.ts.map +1 -0
- package/src/interfaces/ICategoryConfig.js +2 -0
- package/src/interfaces/IMenuConfig.d.ts +28 -0
- package/src/interfaces/IMenuConfig.d.ts.map +1 -0
- package/src/interfaces/IMenuConfig.js +2 -0
- package/src/interfaces/IMenuOption.d.ts +82 -0
- package/src/interfaces/IMenuOption.d.ts.map +1 -0
- package/src/interfaces/IMenuOption.js +2 -0
- package/src/interfaces/{index.ts → index.d.ts} +1 -0
- package/src/interfaces/index.d.ts.map +1 -0
- package/src/interfaces/index.js +7 -0
- package/src/services/__mocks__/authService.d.ts +21 -0
- package/src/services/__mocks__/authService.d.ts.map +1 -0
- package/src/services/__mocks__/authService.js +15 -0
- package/src/services/api.d.ts +3 -0
- package/src/services/api.d.ts.map +1 -0
- package/src/services/api.js +14 -0
- package/src/services/authService.d.ts +126 -0
- package/src/services/authService.d.ts.map +1 -0
- package/src/services/authService.js +471 -0
- package/src/services/authenticatedApi.d.ts +3 -0
- package/src/services/authenticatedApi.d.ts.map +1 -0
- package/src/services/authenticatedApi.js +18 -0
- package/src/services/index.d.ts +4 -0
- package/src/services/index.d.ts.map +1 -0
- package/src/services/index.js +6 -0
- package/src/types/MenuType.d.ts +11 -0
- package/src/types/MenuType.d.ts.map +1 -0
- package/src/types/MenuType.js +12 -0
- package/src/types/expirationSeconds.d.ts +3 -0
- package/src/types/expirationSeconds.d.ts.map +1 -0
- package/src/types/expirationSeconds.js +17 -0
- package/src/types/index.d.ts +2 -0
- package/src/types/index.d.ts.map +1 -0
- package/src/types/index.js +4 -0
- package/src/types/translation.d.ts +10 -0
- package/src/types/translation.d.ts.map +1 -0
- package/src/types/translation.js +9 -0
- package/src/wrappers/BackupCodeLoginWrapper.d.ts +8 -0
- package/src/wrappers/BackupCodeLoginWrapper.d.ts.map +1 -0
- package/src/wrappers/BackupCodeLoginWrapper.js +20 -0
- package/src/wrappers/BackupCodesWrapper.d.ts +7 -0
- package/src/wrappers/BackupCodesWrapper.d.ts.map +1 -0
- package/src/wrappers/BackupCodesWrapper.js +17 -0
- package/src/wrappers/ChangePasswordFormWrapper.d.ts +8 -0
- package/src/wrappers/ChangePasswordFormWrapper.d.ts.map +1 -0
- package/src/wrappers/ChangePasswordFormWrapper.js +21 -0
- package/src/wrappers/ForgotPasswordFormWrapper.d.ts +8 -0
- package/src/wrappers/ForgotPasswordFormWrapper.d.ts.map +1 -0
- package/src/wrappers/ForgotPasswordFormWrapper.js +29 -0
- package/src/wrappers/LoginFormWrapper.d.ts +21 -0
- package/src/wrappers/LoginFormWrapper.d.ts.map +1 -0
- package/src/wrappers/LoginFormWrapper.js +72 -0
- package/src/wrappers/LogoutPageWrapper.d.ts +9 -0
- package/src/wrappers/LogoutPageWrapper.d.ts.map +1 -0
- package/src/wrappers/LogoutPageWrapper.js +21 -0
- package/src/wrappers/RegisterFormWrapper.d.ts +20 -0
- package/src/wrappers/RegisterFormWrapper.d.ts.map +1 -0
- package/src/wrappers/RegisterFormWrapper.js +51 -0
- package/src/wrappers/ResetPasswordFormWrapper.d.ts +9 -0
- package/src/wrappers/ResetPasswordFormWrapper.d.ts.map +1 -0
- package/src/wrappers/ResetPasswordFormWrapper.js +34 -0
- package/src/wrappers/UserSettingsFormWrapper.d.ts +29 -0
- package/src/wrappers/UserSettingsFormWrapper.d.ts.map +1 -0
- package/src/wrappers/UserSettingsFormWrapper.js +95 -0
- package/src/wrappers/VerifyEmailPageWrapper.d.ts +8 -0
- package/src/wrappers/VerifyEmailPageWrapper.d.ts.map +1 -0
- package/src/wrappers/VerifyEmailPageWrapper.js +21 -0
- package/src/wrappers/{index.tsx → index.d.ts} +1 -10
- package/src/wrappers/index.d.ts.map +1 -0
- package/src/wrappers/index.js +24 -0
- package/LICENSE +0 -21
- package/src/auth/AdminRoute.tsx +0 -54
- package/src/auth/Private.tsx +0 -17
- package/src/auth/PrivateRoute.tsx +0 -28
- package/src/auth/UnAuth.tsx +0 -16
- package/src/auth/UnAuthRoute.tsx +0 -30
- package/src/components/ApiAccess.tsx +0 -175
- package/src/components/BackupCodeLoginForm.tsx +0 -489
- package/src/components/BackupCodesForm.tsx +0 -287
- package/src/components/CategoryMenu.tsx +0 -155
- package/src/components/ChangePasswordForm.tsx +0 -273
- package/src/components/ConfirmationDialog.tsx +0 -48
- package/src/components/CurrencyCodeSelector.tsx +0 -60
- package/src/components/CurrencyInput.tsx +0 -80
- package/src/components/DashboardPage.tsx +0 -24
- package/src/components/DropdownMenu.tsx +0 -105
- package/src/components/ExpirationSecondsSelector.tsx +0 -60
- package/src/components/FakeEmailAdminPanel.tsx +0 -374
- package/src/components/Flag.tsx +0 -52
- package/src/components/ForgotPasswordForm.tsx +0 -174
- package/src/components/LoginForm.tsx +0 -468
- package/src/components/LogoutPage.tsx +0 -21
- package/src/components/RegisterForm.tsx +0 -1169
- package/src/components/ResetPasswordForm.tsx +0 -247
- package/src/components/SideMenu.tsx +0 -46
- package/src/components/SideMenuListItem.tsx +0 -75
- package/src/components/T.tsx +0 -24
- package/src/components/TDiv.tsx +0 -26
- package/src/components/TImgAlt.tsx +0 -28
- package/src/components/TopMenu.tsx +0 -252
- package/src/components/TotpSetupForm.tsx +0 -188
- package/src/components/TotpVerificationForm.tsx +0 -148
- package/src/components/TranslatedTitle.tsx +0 -31
- package/src/components/UserLanguageSelector.tsx +0 -45
- package/src/components/UserMenu.tsx +0 -15
- package/src/components/UserSettingsForm.tsx +0 -904
- package/src/components/VerifyEmailPage.tsx +0 -222
- package/src/components/__tests__/RegisterForm.totp.spec.tsx +0 -377
- package/src/components/__tests__/TotpSetupForm.spec.tsx +0 -258
- package/src/components/__tests__/TotpVerificationForm.spec.tsx +0 -259
- package/src/components/__tests__/UserSettingsForm.totp.spec.tsx +0 -396
- package/src/contexts/AuthProvider.spec.tsx +0 -1284
- package/src/contexts/AuthProvider.tsx +0 -977
- package/src/contexts/I18nProvider.tsx +0 -164
- package/src/contexts/MenuContext.tsx +0 -426
- package/src/contexts/SuiteConfigProvider.tsx +0 -93
- package/src/contexts/ThemeProvider.tsx +0 -67
- package/src/hooks/useAuthenticatedApi.tsx +0 -67
- package/src/hooks/useBackupCodes.ts +0 -105
- package/src/hooks/useEmailVerification.ts +0 -54
- package/src/hooks/useExpiringValue.ts +0 -78
- package/src/hooks/useLocalStorage.ts +0 -18
- package/src/hooks/useUserSettings.ts +0 -271
- package/src/interfaces/IAppConfig.ts +0 -7
- package/src/interfaces/ICategoryConfig.ts +0 -41
- package/src/interfaces/IMenuConfig.ts +0 -28
- package/src/interfaces/IMenuOption.ts +0 -79
- package/src/services/__mocks__/authService.ts +0 -14
- package/src/services/__tests__/authService.totp.property.spec.ts +0 -360
- package/src/services/__tests__/authService.totp.spec.ts +0 -439
- package/src/services/api.ts +0 -13
- package/src/services/authService.ts +0 -692
- package/src/services/authenticatedApi.ts +0 -17
- package/src/services/index.ts +0 -3
- package/src/types/MenuType.ts +0 -15
- package/src/types/expirationSeconds.ts +0 -18
- package/src/types/index.ts +0 -1
- package/src/types/translation.ts +0 -20
- package/src/wrappers/BackupCodeLoginWrapper.tsx +0 -34
- package/src/wrappers/BackupCodesWrapper.tsx +0 -28
- package/src/wrappers/ChangePasswordFormWrapper.tsx +0 -34
- package/src/wrappers/ForgotPasswordFormWrapper.tsx +0 -45
- package/src/wrappers/LoginFormWrapper.tsx +0 -108
- package/src/wrappers/LogoutPageWrapper.tsx +0 -30
- package/src/wrappers/RegisterFormWrapper.tsx +0 -109
- package/src/wrappers/ResetPasswordFormWrapper.tsx +0 -57
- package/src/wrappers/UserSettingsFormWrapper.tsx +0 -140
- package/src/wrappers/VerifyEmailPageWrapper.tsx +0 -27
- package/src/wrappers/__tests__/LoginFormWrapper.totp.spec.tsx +0 -339
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SuiteCoreComponentId,
|
|
3
|
-
SuiteCoreStringKey,
|
|
4
|
-
SuiteCoreStringKeyValue,
|
|
5
|
-
} from '@digitaldefiance/suite-core-lib';
|
|
6
|
-
import {
|
|
7
|
-
Alert,
|
|
8
|
-
Box,
|
|
9
|
-
Button,
|
|
10
|
-
CircularProgress,
|
|
11
|
-
Container,
|
|
12
|
-
Link,
|
|
13
|
-
Typography,
|
|
14
|
-
} from '@mui/material';
|
|
15
|
-
import { FC, useEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
-
import { useI18n } from '../contexts';
|
|
17
|
-
|
|
18
|
-
export interface VerifyEmailPageProps {
|
|
19
|
-
token: string | null;
|
|
20
|
-
onVerify: (token: string) => Promise<{ success: boolean; message?: string }>;
|
|
21
|
-
labels?: {
|
|
22
|
-
title?: string;
|
|
23
|
-
verifying?: string;
|
|
24
|
-
success?: string;
|
|
25
|
-
failed?: string;
|
|
26
|
-
noToken?: string;
|
|
27
|
-
checkYourEmail?: string;
|
|
28
|
-
proceedToLogin?: string;
|
|
29
|
-
contactSupport?: string;
|
|
30
|
-
requestNewEmail?: string;
|
|
31
|
-
};
|
|
32
|
-
loginLink?: string;
|
|
33
|
-
resendLink?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const VerifyEmailPage: FC<VerifyEmailPageProps> = ({
|
|
37
|
-
token,
|
|
38
|
-
onVerify,
|
|
39
|
-
labels = {},
|
|
40
|
-
loginLink = '/login',
|
|
41
|
-
resendLink = '/resend-verification',
|
|
42
|
-
}) => {
|
|
43
|
-
const { tComponent } = useI18n();
|
|
44
|
-
const [message, setMessage] = useState('');
|
|
45
|
-
const [loading, setLoading] = useState(true);
|
|
46
|
-
const [verificationStatus, setVerificationStatus] = useState<
|
|
47
|
-
'pending' | 'success' | 'error' | 'info'
|
|
48
|
-
>('pending');
|
|
49
|
-
|
|
50
|
-
const translatedLabels = useMemo<{
|
|
51
|
-
title: string;
|
|
52
|
-
success: string;
|
|
53
|
-
failed: string;
|
|
54
|
-
noToken: string;
|
|
55
|
-
checkYourEmail: string;
|
|
56
|
-
proceedToLogin: string;
|
|
57
|
-
contactSupport: string;
|
|
58
|
-
requestNewEmail: string;
|
|
59
|
-
}>(() => {
|
|
60
|
-
return {
|
|
61
|
-
title:
|
|
62
|
-
labels.title ||
|
|
63
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
64
|
-
SuiteCoreComponentId,
|
|
65
|
-
SuiteCoreStringKey.Common_EmailVerification
|
|
66
|
-
),
|
|
67
|
-
success:
|
|
68
|
-
labels.success ||
|
|
69
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
70
|
-
SuiteCoreComponentId,
|
|
71
|
-
SuiteCoreStringKey.EmailVerification_Success
|
|
72
|
-
),
|
|
73
|
-
failed:
|
|
74
|
-
labels.failed ||
|
|
75
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
76
|
-
SuiteCoreComponentId,
|
|
77
|
-
SuiteCoreStringKey.EmailVerification_Failed
|
|
78
|
-
),
|
|
79
|
-
noToken:
|
|
80
|
-
labels.noToken ||
|
|
81
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
82
|
-
SuiteCoreComponentId,
|
|
83
|
-
SuiteCoreStringKey.NoVerificationTokenProvided
|
|
84
|
-
),
|
|
85
|
-
checkYourEmail:
|
|
86
|
-
labels.checkYourEmail ||
|
|
87
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
88
|
-
SuiteCoreComponentId,
|
|
89
|
-
SuiteCoreStringKey.Registration_CheckYourEmail
|
|
90
|
-
),
|
|
91
|
-
proceedToLogin:
|
|
92
|
-
labels.proceedToLogin ||
|
|
93
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
94
|
-
SuiteCoreComponentId,
|
|
95
|
-
SuiteCoreStringKey.ProceedToLogin
|
|
96
|
-
),
|
|
97
|
-
contactSupport:
|
|
98
|
-
labels.contactSupport ||
|
|
99
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
100
|
-
SuiteCoreComponentId,
|
|
101
|
-
SuiteCoreStringKey.HavingTroubleContactSupport
|
|
102
|
-
),
|
|
103
|
-
requestNewEmail:
|
|
104
|
-
labels.requestNewEmail ||
|
|
105
|
-
tComponent<SuiteCoreStringKeyValue>(
|
|
106
|
-
SuiteCoreComponentId,
|
|
107
|
-
SuiteCoreStringKey.RequestNewVerificationEmail
|
|
108
|
-
),
|
|
109
|
-
};
|
|
110
|
-
}, [labels, tComponent]);
|
|
111
|
-
|
|
112
|
-
// Use a ref to track whether verification has already been attempted,
|
|
113
|
-
// preventing infinite re-render loops from unstable onVerify references.
|
|
114
|
-
const hasVerified = useRef(false);
|
|
115
|
-
|
|
116
|
-
// Stable reference to onVerify to avoid re-triggering the effect
|
|
117
|
-
const onVerifyRef = useRef(onVerify);
|
|
118
|
-
onVerifyRef.current = onVerify;
|
|
119
|
-
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (hasVerified.current) return;
|
|
122
|
-
|
|
123
|
-
if (token) {
|
|
124
|
-
hasVerified.current = true;
|
|
125
|
-
const verifyEmail = async () => {
|
|
126
|
-
try {
|
|
127
|
-
const result = await onVerifyRef.current(token);
|
|
128
|
-
if (result.success) {
|
|
129
|
-
setMessage(result.message || translatedLabels.success);
|
|
130
|
-
setVerificationStatus('success');
|
|
131
|
-
} else {
|
|
132
|
-
setMessage(result.message || translatedLabels.failed);
|
|
133
|
-
setVerificationStatus('error');
|
|
134
|
-
}
|
|
135
|
-
} catch {
|
|
136
|
-
setMessage(translatedLabels.failed);
|
|
137
|
-
setVerificationStatus('error');
|
|
138
|
-
} finally {
|
|
139
|
-
setLoading(false);
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
verifyEmail();
|
|
143
|
-
} else {
|
|
144
|
-
hasVerified.current = true;
|
|
145
|
-
setLoading(false);
|
|
146
|
-
setVerificationStatus('info');
|
|
147
|
-
}
|
|
148
|
-
}, [token, translatedLabels]);
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<Container maxWidth="sm">
|
|
152
|
-
<Box
|
|
153
|
-
sx={{
|
|
154
|
-
mt: 8,
|
|
155
|
-
display: 'flex',
|
|
156
|
-
flexDirection: 'column',
|
|
157
|
-
alignItems: 'center',
|
|
158
|
-
}}
|
|
159
|
-
>
|
|
160
|
-
<Typography variant="h4" component="h1" gutterBottom>
|
|
161
|
-
{translatedLabels.title}
|
|
162
|
-
</Typography>
|
|
163
|
-
|
|
164
|
-
{loading ? (
|
|
165
|
-
<CircularProgress />
|
|
166
|
-
) : (
|
|
167
|
-
<Box sx={{ width: '100%', mt: 2 }}>
|
|
168
|
-
{verificationStatus === 'info' ? (
|
|
169
|
-
<>
|
|
170
|
-
<Alert severity="info" sx={{ mb: 2 }}>
|
|
171
|
-
{translatedLabels.noToken}
|
|
172
|
-
</Alert>
|
|
173
|
-
<Typography variant="body1">
|
|
174
|
-
{translatedLabels.contactSupport}{' '}
|
|
175
|
-
<Link href={resendLink} color="primary">
|
|
176
|
-
{translatedLabels.requestNewEmail}
|
|
177
|
-
</Link>
|
|
178
|
-
.
|
|
179
|
-
</Typography>
|
|
180
|
-
</>
|
|
181
|
-
) : (
|
|
182
|
-
<>
|
|
183
|
-
<Alert
|
|
184
|
-
severity={
|
|
185
|
-
verificationStatus === 'success' ? 'success' : 'error'
|
|
186
|
-
}
|
|
187
|
-
sx={{ mb: 2 }}
|
|
188
|
-
>
|
|
189
|
-
{message}
|
|
190
|
-
</Alert>
|
|
191
|
-
|
|
192
|
-
{verificationStatus === 'success' && (
|
|
193
|
-
<Button
|
|
194
|
-
variant="contained"
|
|
195
|
-
color="primary"
|
|
196
|
-
component={Link}
|
|
197
|
-
href={loginLink}
|
|
198
|
-
fullWidth
|
|
199
|
-
>
|
|
200
|
-
{translatedLabels.proceedToLogin}
|
|
201
|
-
</Button>
|
|
202
|
-
)}
|
|
203
|
-
|
|
204
|
-
{verificationStatus === 'error' && (
|
|
205
|
-
<Typography variant="body1">
|
|
206
|
-
{translatedLabels.contactSupport}{' '}
|
|
207
|
-
<Link href={resendLink} color="primary">
|
|
208
|
-
{translatedLabels.requestNewEmail}
|
|
209
|
-
</Link>
|
|
210
|
-
.
|
|
211
|
-
</Typography>
|
|
212
|
-
)}
|
|
213
|
-
</>
|
|
214
|
-
)}
|
|
215
|
-
</Box>
|
|
216
|
-
)}
|
|
217
|
-
</Box>
|
|
218
|
-
</Container>
|
|
219
|
-
);
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
export default VerifyEmailPage;
|
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
2
|
-
import { RegisterForm } from '../RegisterForm';
|
|
3
|
-
import { I18nProvider } from '../../contexts';
|
|
4
|
-
import { I18nEngine } from '@digitaldefiance/i18n-lib';
|
|
5
|
-
|
|
6
|
-
// Mock qrcode.react to avoid SVG rendering complexity in jsdom
|
|
7
|
-
jest.mock('qrcode.react', () => ({
|
|
8
|
-
QRCodeSVG: (props: Record<string, unknown>) => (
|
|
9
|
-
<svg
|
|
10
|
-
data-testid="qr-code-svg"
|
|
11
|
-
role={props.role as string}
|
|
12
|
-
aria-label={props['aria-label'] as string}
|
|
13
|
-
/>
|
|
14
|
-
),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
const mockTimezones = [
|
|
18
|
-
'America/New_York',
|
|
19
|
-
'America/Los_Angeles',
|
|
20
|
-
'Europe/London',
|
|
21
|
-
'UTC',
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const mockGetInitialTimezone = (): string => 'UTC';
|
|
25
|
-
|
|
26
|
-
const renderWithI18n = (component: React.ReactElement) => {
|
|
27
|
-
const engine = I18nEngine.getInstance('default');
|
|
28
|
-
return render(<I18nProvider i18nEngine={engine}>{component}</I18nProvider>);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Helper: fill the registration form with valid data and submit.
|
|
33
|
-
*/
|
|
34
|
-
const fillAndSubmitRegistration = async () => {
|
|
35
|
-
fireEvent.change(screen.getByLabelText(/username/i), {
|
|
36
|
-
target: { value: 'testuser' },
|
|
37
|
-
});
|
|
38
|
-
fireEvent.change(screen.getByLabelText(/email/i), {
|
|
39
|
-
target: { value: 'test@example.com' },
|
|
40
|
-
});
|
|
41
|
-
fireEvent.change(screen.getByLabelText(/display name/i), {
|
|
42
|
-
target: { value: 'Test User' },
|
|
43
|
-
});
|
|
44
|
-
fireEvent.change(screen.getByLabelText(/^password/i), {
|
|
45
|
-
target: { value: 'Password123!' },
|
|
46
|
-
});
|
|
47
|
-
fireEvent.change(screen.getByLabelText(/confirm/i), {
|
|
48
|
-
target: { value: 'Password123!' },
|
|
49
|
-
});
|
|
50
|
-
fireEvent.click(screen.getByRole('button', { name: /register/i }));
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
describe('RegisterForm TOTP integration', () => {
|
|
54
|
-
// Suppress act() warnings from Formik's internal state management
|
|
55
|
-
const originalError = console.error;
|
|
56
|
-
beforeAll(() => {
|
|
57
|
-
console.error = (...args: unknown[]) => {
|
|
58
|
-
if (
|
|
59
|
-
typeof args[0] === 'string' &&
|
|
60
|
-
args[0].includes('not wrapped in act')
|
|
61
|
-
) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
originalError.call(console, ...args);
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
afterAll(() => {
|
|
69
|
-
console.error = originalError;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
jest.clearAllMocks();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Validates: Requirement 14.3
|
|
78
|
-
* No TOTP UI when enableTotpSetup is not passed (backward compatible).
|
|
79
|
-
*/
|
|
80
|
-
it('does not show TOTP setup when enableTotpSetup is not passed', async () => {
|
|
81
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
82
|
-
success: true,
|
|
83
|
-
message: 'Registered',
|
|
84
|
-
mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
renderWithI18n(
|
|
88
|
-
<RegisterForm
|
|
89
|
-
timezones={mockTimezones}
|
|
90
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
91
|
-
onSubmit={mockOnSubmit}
|
|
92
|
-
/>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
await fillAndSubmitRegistration();
|
|
96
|
-
|
|
97
|
-
await waitFor(() => {
|
|
98
|
-
expect(mockOnSubmit).toHaveBeenCalled();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Should NOT show TOTP setup UI
|
|
102
|
-
expect(
|
|
103
|
-
screen.queryByText(/set up two-factor authentication/i)
|
|
104
|
-
).not.toBeInTheDocument();
|
|
105
|
-
expect(screen.queryByTestId('skip-totp-button')).not.toBeInTheDocument();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Validates: Requirement 14.3
|
|
110
|
-
* No TOTP UI when enableTotpSetup is explicitly false.
|
|
111
|
-
*/
|
|
112
|
-
it('does not show TOTP setup when enableTotpSetup is false', async () => {
|
|
113
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
114
|
-
success: true,
|
|
115
|
-
message: 'Registered',
|
|
116
|
-
mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
renderWithI18n(
|
|
120
|
-
<RegisterForm
|
|
121
|
-
timezones={mockTimezones}
|
|
122
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
123
|
-
onSubmit={mockOnSubmit}
|
|
124
|
-
enableTotpSetup={false}
|
|
125
|
-
/>
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
await fillAndSubmitRegistration();
|
|
129
|
-
|
|
130
|
-
await waitFor(() => {
|
|
131
|
-
expect(mockOnSubmit).toHaveBeenCalled();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(
|
|
135
|
-
screen.queryByText(/set up two-factor authentication/i)
|
|
136
|
-
).not.toBeInTheDocument();
|
|
137
|
-
expect(screen.queryByTestId('skip-totp-button')).not.toBeInTheDocument();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Validates: Requirement 7.1
|
|
142
|
-
* TOTP setup step is shown after successful registration when enableTotpSetup=true.
|
|
143
|
-
*/
|
|
144
|
-
it('shows TOTP setup step after successful registration when enableTotpSetup=true', async () => {
|
|
145
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
146
|
-
success: true,
|
|
147
|
-
message: 'Registered',
|
|
148
|
-
});
|
|
149
|
-
const mockOnTotpSetup = jest.fn().mockResolvedValue({
|
|
150
|
-
provisioningUri:
|
|
151
|
-
'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
|
|
152
|
-
secret: 'JBSWY3DPEHPK3PXP',
|
|
153
|
-
});
|
|
154
|
-
const mockOnTotpConfirm = jest
|
|
155
|
-
.fn()
|
|
156
|
-
.mockResolvedValue({ success: true });
|
|
157
|
-
|
|
158
|
-
renderWithI18n(
|
|
159
|
-
<RegisterForm
|
|
160
|
-
timezones={mockTimezones}
|
|
161
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
162
|
-
onSubmit={mockOnSubmit}
|
|
163
|
-
enableTotpSetup={true}
|
|
164
|
-
onTotpSetup={mockOnTotpSetup}
|
|
165
|
-
onTotpConfirm={mockOnTotpConfirm}
|
|
166
|
-
/>
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
await fillAndSubmitRegistration();
|
|
170
|
-
|
|
171
|
-
await waitFor(() => {
|
|
172
|
-
expect(mockOnTotpSetup).toHaveBeenCalled();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// TOTP setup UI should be visible (text appears in both RegisterForm heading and TotpSetupForm heading)
|
|
176
|
-
await waitFor(() => {
|
|
177
|
-
expect(
|
|
178
|
-
screen.getAllByText(/set up two-factor authentication/i).length
|
|
179
|
-
).toBeGreaterThanOrEqual(1);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// QR code and secret should be rendered
|
|
183
|
-
expect(screen.getByTestId('qr-code-svg')).toBeInTheDocument();
|
|
184
|
-
expect(screen.getByText('JBSWY3DPEHPK3PXP')).toBeInTheDocument();
|
|
185
|
-
|
|
186
|
-
// Skip button should be present
|
|
187
|
-
expect(screen.getByTestId('skip-totp-button')).toBeInTheDocument();
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Validates: Requirement 7.2
|
|
192
|
-
* TOTP setup step is skippable — clicking Skip proceeds to post-registration flow.
|
|
193
|
-
*/
|
|
194
|
-
it('allows skipping TOTP setup via the Skip button', async () => {
|
|
195
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
196
|
-
success: true,
|
|
197
|
-
message: 'Registered',
|
|
198
|
-
mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
|
|
199
|
-
});
|
|
200
|
-
const mockOnTotpSetup = jest.fn().mockResolvedValue({
|
|
201
|
-
provisioningUri:
|
|
202
|
-
'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
|
|
203
|
-
secret: 'JBSWY3DPEHPK3PXP',
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
renderWithI18n(
|
|
207
|
-
<RegisterForm
|
|
208
|
-
timezones={mockTimezones}
|
|
209
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
210
|
-
onSubmit={mockOnSubmit}
|
|
211
|
-
enableTotpSetup={true}
|
|
212
|
-
onTotpSetup={mockOnTotpSetup}
|
|
213
|
-
onTotpConfirm={jest.fn()}
|
|
214
|
-
/>
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
await fillAndSubmitRegistration();
|
|
218
|
-
|
|
219
|
-
// Wait for TOTP setup to appear (text appears in both RegisterForm heading and TotpSetupForm heading)
|
|
220
|
-
await waitFor(() => {
|
|
221
|
-
expect(
|
|
222
|
-
screen.getAllByText(/set up two-factor authentication/i).length
|
|
223
|
-
).toBeGreaterThanOrEqual(1);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// Click Skip
|
|
227
|
-
fireEvent.click(screen.getByTestId('skip-totp-button'));
|
|
228
|
-
|
|
229
|
-
// TOTP setup should be hidden, post-registration flow should show
|
|
230
|
-
await waitFor(() => {
|
|
231
|
-
expect(
|
|
232
|
-
screen.queryAllByText(/set up two-factor authentication/i)
|
|
233
|
-
).toHaveLength(0);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Mnemonic display (post-registration flow) should be visible
|
|
237
|
-
expect(screen.getByText('word1')).toBeInTheDocument();
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Validates: Requirement 7.5
|
|
242
|
-
* onTotpSetupComplete is called after successful TOTP confirmation.
|
|
243
|
-
*/
|
|
244
|
-
it('calls onTotpSetupComplete after successful TOTP confirmation', async () => {
|
|
245
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
246
|
-
success: true,
|
|
247
|
-
message: 'Registered',
|
|
248
|
-
});
|
|
249
|
-
const mockOnTotpSetup = jest.fn().mockResolvedValue({
|
|
250
|
-
provisioningUri:
|
|
251
|
-
'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
|
|
252
|
-
secret: 'JBSWY3DPEHPK3PXP',
|
|
253
|
-
});
|
|
254
|
-
const mockOnTotpConfirm = jest
|
|
255
|
-
.fn()
|
|
256
|
-
.mockResolvedValue({ success: true });
|
|
257
|
-
const mockOnTotpSetupComplete = jest.fn();
|
|
258
|
-
|
|
259
|
-
renderWithI18n(
|
|
260
|
-
<RegisterForm
|
|
261
|
-
timezones={mockTimezones}
|
|
262
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
263
|
-
onSubmit={mockOnSubmit}
|
|
264
|
-
enableTotpSetup={true}
|
|
265
|
-
onTotpSetup={mockOnTotpSetup}
|
|
266
|
-
onTotpConfirm={mockOnTotpConfirm}
|
|
267
|
-
onTotpSetupComplete={mockOnTotpSetupComplete}
|
|
268
|
-
/>
|
|
269
|
-
);
|
|
270
|
-
|
|
271
|
-
await fillAndSubmitRegistration();
|
|
272
|
-
|
|
273
|
-
// Wait for TOTP setup to appear
|
|
274
|
-
await waitFor(() => {
|
|
275
|
-
expect(screen.getByTestId('qr-code-svg')).toBeInTheDocument();
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// Enter a 6-digit code and confirm
|
|
279
|
-
const codeInput = screen.getByLabelText(/confirmation code/i);
|
|
280
|
-
fireEvent.change(codeInput, { target: { value: '123456' } });
|
|
281
|
-
fireEvent.click(screen.getByRole('button', { name: /confirm/i }));
|
|
282
|
-
|
|
283
|
-
await waitFor(() => {
|
|
284
|
-
expect(mockOnTotpConfirm).toHaveBeenCalledWith('123456');
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
await waitFor(() => {
|
|
288
|
-
expect(mockOnTotpSetupComplete).toHaveBeenCalled();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// TOTP setup should be hidden after success, success message shown
|
|
292
|
-
await waitFor(() => {
|
|
293
|
-
expect(
|
|
294
|
-
screen.getByText(/two-factor authentication has been enabled/i)
|
|
295
|
-
).toBeInTheDocument();
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Validates: Requirement 7.4
|
|
301
|
-
* Error handling: displays error when onTotpSetup returns an error.
|
|
302
|
-
*/
|
|
303
|
-
it('displays error when TOTP setup initiation fails', async () => {
|
|
304
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
305
|
-
success: true,
|
|
306
|
-
message: 'Registered',
|
|
307
|
-
});
|
|
308
|
-
const mockOnTotpSetup = jest
|
|
309
|
-
.fn()
|
|
310
|
-
.mockResolvedValue({ error: 'Setup service unavailable' });
|
|
311
|
-
|
|
312
|
-
renderWithI18n(
|
|
313
|
-
<RegisterForm
|
|
314
|
-
timezones={mockTimezones}
|
|
315
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
316
|
-
onSubmit={mockOnSubmit}
|
|
317
|
-
enableTotpSetup={true}
|
|
318
|
-
onTotpSetup={mockOnTotpSetup}
|
|
319
|
-
onTotpConfirm={jest.fn()}
|
|
320
|
-
/>
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
await fillAndSubmitRegistration();
|
|
324
|
-
|
|
325
|
-
await waitFor(() => {
|
|
326
|
-
expect(mockOnTotpSetup).toHaveBeenCalled();
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// Error message should be displayed
|
|
330
|
-
await waitFor(() => {
|
|
331
|
-
expect(
|
|
332
|
-
screen.getByText('Setup service unavailable')
|
|
333
|
-
).toBeInTheDocument();
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// Skip button should still be available to proceed
|
|
337
|
-
expect(screen.getByTestId('skip-totp-button')).toBeInTheDocument();
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Validates: Requirement 7.4
|
|
342
|
-
* Error handling: displays fallback error when onTotpSetup throws.
|
|
343
|
-
*/
|
|
344
|
-
it('displays fallback error when TOTP setup throws an exception', async () => {
|
|
345
|
-
const mockOnSubmit = jest.fn().mockResolvedValue({
|
|
346
|
-
success: true,
|
|
347
|
-
message: 'Registered',
|
|
348
|
-
});
|
|
349
|
-
const mockOnTotpSetup = jest
|
|
350
|
-
.fn()
|
|
351
|
-
.mockRejectedValue(new Error('Network error'));
|
|
352
|
-
|
|
353
|
-
renderWithI18n(
|
|
354
|
-
<RegisterForm
|
|
355
|
-
timezones={mockTimezones}
|
|
356
|
-
getInitialTimezone={mockGetInitialTimezone}
|
|
357
|
-
onSubmit={mockOnSubmit}
|
|
358
|
-
enableTotpSetup={true}
|
|
359
|
-
onTotpSetup={mockOnTotpSetup}
|
|
360
|
-
onTotpConfirm={jest.fn()}
|
|
361
|
-
/>
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
await fillAndSubmitRegistration();
|
|
365
|
-
|
|
366
|
-
await waitFor(() => {
|
|
367
|
-
expect(mockOnTotpSetup).toHaveBeenCalled();
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
// Fallback error message should be displayed
|
|
371
|
-
await waitFor(() => {
|
|
372
|
-
expect(
|
|
373
|
-
screen.getByText(/failed to set up two-factor authentication/i)
|
|
374
|
-
).toBeInTheDocument();
|
|
375
|
-
});
|
|
376
|
-
});
|
|
377
|
-
});
|