diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index e7f7cff62dd5..78daa0c31e50 100755
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -5469,6 +5469,10 @@ const CONST = {
         DISABLED: 'DISABLED',
         DISABLE: 'DISABLE',
     },
+    MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE: {
+        SUCCESS: 'success',
+        FAILURE: 'failure',
+    },
     MERGE_ACCOUNT_RESULTS: {
         SUCCESS: 'success',
         ERR_2FA: 'err_2fa',
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 1799b9078b2b..87990bbe91f8 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -51,6 +51,11 @@ const PUBLIC_SCREENS_ROUTES = {
 // Exported for identifying a url as a verify-account route, associated with a page extending the VerifyAccountPageBase component
 const VERIFY_ACCOUNT = 'verify-account';
 
+const MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES = {
+    FACTOR: 'multifactor-authentication/factor',
+    PROMPT: 'multifactor-authentication/prompt',
+} as const;
+
 const ROUTES = {
     ...PUBLIC_SCREENS_ROUTES,
     // This route renders the list of reports.
@@ -3685,6 +3690,23 @@ const ROUTES = {
         route: 'domain/:domainAccountID/admins/:accountID/reset-domain',
         getRoute: (domainAccountID: number, accountID: number) => `domain/${domainAccountID}/admins/${accountID}/reset-domain` as const,
     },
+
+    MULTIFACTOR_AUTHENTICATION_MAGIC_CODE: `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.FACTOR}/magic-code`,
+    MULTIFACTOR_AUTHENTICATION_BIOMETRICS_TEST: 'multifactor-authentication/scenario/biometrics-test',
+
+    // The exact notification & prompt type will be added as a part of Multifactor Authentication config in another PR,
+    // for now a string is accepted to avoid blocking this PR.
+    MULTIFACTOR_AUTHENTICATION_NOTIFICATION: {
+        route: 'multifactor-authentication/notification/:notificationType',
+        getRoute: (notificationType: ValueOf<typeof CONST.MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE>) => `multifactor-authentication/notification/${notificationType}` as const,
+    },
+
+    MULTIFACTOR_AUTHENTICATION_PROMPT: {
+        route: `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.PROMPT}/:promptType`,
+        getRoute: (promptType: string) => `${MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES.PROMPT}/${promptType}` as const,
+    },
+
+    MULTIFACTOR_AUTHENTICATION_NOT_FOUND: 'multifactor-authentication/not-found',
 } as const;
 
 /**
@@ -3700,7 +3722,7 @@ const SHARED_ROUTE_PARAMS: Partial<Record<Screen, string[]>> = {
     [SCREENS.WORKSPACE.INITIAL]: ['backTo'],
 } as const;
 
-export {PUBLIC_SCREENS_ROUTES, SHARED_ROUTE_PARAMS, VERIFY_ACCOUNT};
+export {PUBLIC_SCREENS_ROUTES, SHARED_ROUTE_PARAMS, VERIFY_ACCOUNT, MULTIFACTOR_AUTHENTICATION_PROTECTED_ROUTES};
 export default ROUTES;
 
 type ReportAttachmentsRoute = typeof ROUTES.REPORT_ATTACHMENTS.route;
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index c6f861e0666d..9744c56eac72 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -276,6 +276,7 @@ const SCREENS = {
         REPORT_CARD_ACTIVATE: 'Report_Card_Activate',
         DOMAIN: 'Domain',
         EXPENSE_REPORT: 'ExpenseReport',
+        MULTIFACTOR_AUTHENTICATION: 'MultifactorAuthentication',
     },
     REPORT_CARD_ACTIVATE: 'Report_Card_Activate_Root',
     PUBLIC_CONSOLE_DEBUG: 'Console_Debug',
@@ -883,6 +884,13 @@ const SCREENS = {
         MEMBER_DETAILS: 'Member_Details',
         RESET_DOMAIN: 'Domain_Reset',
     },
+    MULTIFACTOR_AUTHENTICATION: {
+        MAGIC_CODE: 'Multifactor_Authentication_Magic_Code',
+        BIOMETRICS_TEST: 'Multifactor_Authentication_Biometrics_Test',
+        NOTIFICATION: 'Multifactor_Authentication_Notification',
+        PROMPT: 'Multifactor_Authentication_Prompt',
+        NOT_FOUND: 'Multifactor_Authentication_Not_Found',
+    },
 } as const;
 
 type Screen = DeepValueOf<typeof SCREENS>;
diff --git a/src/components/MultifactorAuthentication/NoEligibleMethodsDescription.tsx b/src/components/MultifactorAuthentication/NoEligibleMethodsDescription.tsx
new file mode 100644
index 000000000000..b1dcab2c7dca
--- /dev/null
+++ b/src/components/MultifactorAuthentication/NoEligibleMethodsDescription.tsx
@@ -0,0 +1,34 @@
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import goToSettings from '@libs/goToSettings';
+
+const baseTranslationPath = 'multifactorAuthentication.pleaseEnableInSystemSettings' as const;
+
+const translationPaths = {
+    start: `${baseTranslationPath}.start`,
+    link: `${baseTranslationPath}.link`,
+    end: `${baseTranslationPath}.end`,
+} as const;
+
+function NoEligibleMethodsDescription() {
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+
+    const start = translate(translationPaths.start);
+    const link = translate(translationPaths.link);
+    const end = translate(translationPaths.end);
+
+    return (
+        <Text style={[styles.textAlignCenter, styles.textSupporting]}>
+            {start}
+            <TextLink onPress={goToSettings}>{link}</TextLink>
+            {end}
+        </Text>
+    );
+}
+
+NoEligibleMethodsDescription.displayName = 'NoEligibleMethodsDescription';
+
+export default NoEligibleMethodsDescription;
diff --git a/src/components/MultifactorAuthentication/PromptContent.tsx b/src/components/MultifactorAuthentication/PromptContent.tsx
new file mode 100644
index 000000000000..2d91ff96d1d4
--- /dev/null
+++ b/src/components/MultifactorAuthentication/PromptContent.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import {View} from 'react-native';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import type DotLottieAnimation from '@components/LottieAnimations/types';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type {TranslationPaths} from '@src/languages/types';
+
+type MultifactorAuthenticationPromptContentProps = {
+    animation: DotLottieAnimation;
+    title: TranslationPaths;
+    subtitle: TranslationPaths;
+};
+
+function MultifactorAuthenticationPromptContent({title, subtitle, animation}: MultifactorAuthenticationPromptContentProps) {
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+
+    return (
+        <View style={styles.flex1}>
+            <BlockingView
+                animation={animation}
+                animationStyles={styles.mfaBlockingViewAnimation}
+                animationWebStyle={styles.mfaBlockingViewAnimation}
+                title={translate(title)}
+                titleStyles={styles.mb2}
+                subtitle={translate(subtitle)}
+                subtitleStyle={styles.textSupporting}
+                containerStyle={styles.ph5}
+                testID="MultifactorAuthenticationPromptContent"
+            />
+        </View>
+    );
+}
+
+MultifactorAuthenticationPromptContent.displayName = 'MultifactorAuthenticationPromptContent';
+
+export default MultifactorAuthenticationPromptContent;
diff --git a/src/components/MultifactorAuthentication/TriggerCancelConfirmModal.tsx b/src/components/MultifactorAuthentication/TriggerCancelConfirmModal.tsx
new file mode 100644
index 000000000000..819b38507497
--- /dev/null
+++ b/src/components/MultifactorAuthentication/TriggerCancelConfirmModal.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import ConfirmModal from '@components/ConfirmModal';
+import useLocalize from '@hooks/useLocalize';
+import type {TranslationPaths} from '@src/languages/types';
+
+type MultifactorAuthenticationTriggerCancelConfirmModalProps = {
+    isVisible: boolean;
+    onConfirm: () => void;
+    onCancel: () => void;
+};
+
+// TODO: this config will be part of the scenario configuration, the current implementation is for testing purposes (https://github.com/Expensify/App/issues/79373)
+const mockedConfig = {
+    title: 'common.areYouSure',
+    description: 'multifactorAuthentication.biometricsTest.areYouSureToReject',
+    confirmButtonText: 'multifactorAuthentication.biometricsTest.rejectAuthentication',
+    cancelButtonText: 'common.cancel',
+} as const satisfies Record<string, TranslationPaths>;
+
+function MultifactorAuthenticationTriggerCancelConfirmModal({isVisible, onConfirm, onCancel}: MultifactorAuthenticationTriggerCancelConfirmModalProps) {
+    const {translate} = useLocalize();
+
+    const title = translate(mockedConfig.title);
+    const description = translate(mockedConfig.description);
+    const confirmButtonText = translate(mockedConfig.confirmButtonText);
+    const cancelButtonText = translate(mockedConfig.cancelButtonText);
+
+    return (
+        <ConfirmModal
+            danger
+            title={title}
+            onConfirm={onConfirm}
+            onCancel={onCancel}
+            isVisible={isVisible}
+            prompt={description}
+            confirmText={confirmButtonText}
+            cancelText={cancelButtonText}
+            shouldShowCancelButton
+        />
+    );
+}
+
+MultifactorAuthenticationTriggerCancelConfirmModal.displayName = 'MultifactorAuthenticationTriggerCancelConfirmModal';
+
+export default MultifactorAuthenticationTriggerCancelConfirmModal;
diff --git a/src/components/MultifactorAuthentication/ValidateCodeResendButton.tsx b/src/components/MultifactorAuthentication/ValidateCodeResendButton.tsx
new file mode 100644
index 000000000000..e129d4461e18
--- /dev/null
+++ b/src/components/MultifactorAuthentication/ValidateCodeResendButton.tsx
@@ -0,0 +1,84 @@
+import React, {useCallback, useImperativeHandle, useRef, useState} from 'react';
+import {View} from 'react-native';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import ValidateCodeCountdown from '@components/ValidateCodeCountdown';
+import type {ValidateCodeCountdownHandle} from '@components/ValidateCodeCountdown/types';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+
+type MultifactorAuthenticationValidateCodeResendButtonHandle = {
+    resetCountdown: () => void;
+};
+
+type MultifactorAuthenticationValidateCodeResendButtonProps = {
+    ref?: React.Ref<MultifactorAuthenticationValidateCodeResendButtonHandle>;
+    shouldDisableResendCode: boolean;
+    hasError: boolean;
+    resendButtonText: TranslationPaths;
+    onResendValidationCode: () => void;
+};
+
+function MultifactorAuthenticationValidateCodeResendButton({
+    ref,
+    shouldDisableResendCode,
+    hasError,
+    resendButtonText,
+    onResendValidationCode,
+}: MultifactorAuthenticationValidateCodeResendButtonProps) {
+    const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
+    const {translate} = useLocalize();
+    const {isOffline} = useNetwork();
+
+    const [isCountdownRunning, setIsCountdownRunning] = useState(true);
+    const countdownRef = useRef<ValidateCodeCountdownHandle>(null);
+
+    const handleCountdownFinish = useCallback(() => {
+        setIsCountdownRunning(false);
+    }, []);
+
+    useImperativeHandle(ref, () => ({
+        resetCountdown: () => {
+            countdownRef.current?.resetCountdown();
+            setIsCountdownRunning(true);
+        },
+    }));
+
+    return (
+        <View style={styles.alignItemsStart}>
+            {isCountdownRunning && !isOffline ? (
+                <View style={[styles.mt5, styles.flexRow, styles.renderHTML]}>
+                    <ValidateCodeCountdown
+                        ref={countdownRef}
+                        onCountdownFinish={handleCountdownFinish}
+                    />
+                </View>
+            ) : (
+                <PressableWithFeedback
+                    style={styles.mt5}
+                    onPress={onResendValidationCode}
+                    disabled={shouldDisableResendCode}
+                    hoverDimmingValue={1}
+                    pressDimmingValue={0.2}
+                    role={CONST.ROLE.BUTTON}
+                    accessibilityLabel={translate(resendButtonText)}
+                >
+                    <Text style={[StyleUtils.getDisabledLinkStyles(shouldDisableResendCode)]}>
+                        {hasError ? translate('validateCodeForm.requestNewCodeAfterErrorOccurred') : translate(resendButtonText)}
+                    </Text>
+                </PressableWithFeedback>
+            )}
+        </View>
+    );
+}
+
+MultifactorAuthenticationValidateCodeResendButton.displayName = 'MultifactorAuthenticationValidateCodeResendButton';
+
+export default MultifactorAuthenticationValidateCodeResendButton;
+
+export type {MultifactorAuthenticationValidateCodeResendButtonHandle};
diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx
index d31450a02250..f4f83bfab000 100644
--- a/src/components/TestToolMenu.tsx
+++ b/src/components/TestToolMenu.tsx
@@ -1,15 +1,20 @@
 import React from 'react';
+import {View} from 'react-native';
 import useIsAuthenticated from '@hooks/useIsAuthenticated';
 import useLocalize from '@hooks/useLocalize';
 import useOnyx from '@hooks/useOnyx';
 import {useSidebarOrderedReports} from '@hooks/useSidebarOrderedReports';
+import useSingleExecution from '@hooks/useSingleExecution';
 import useThemeStyles from '@hooks/useThemeStyles';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
 import {isUsingStagingApi} from '@libs/ApiUtils';
+import Navigation from '@libs/Navigation/Navigation';
 import {setShouldFailAllRequests, setShouldForceOffline, setShouldSimulatePoorConnection} from '@userActions/Network';
 import {expireSessionWithDelay, invalidateAuthToken, invalidateCredentials} from '@userActions/Session';
 import {setIsDebugModeEnabled, setShouldUseStagingServer} from '@userActions/User';
 import CONFIG from '@src/CONFIG';
 import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
 import Button from './Button';
 import SoftKillTestToolRow from './SoftKillTestToolRow';
 import Switch from './Switch';
@@ -26,9 +31,20 @@ function TestToolMenu() {
     const {translate} = useLocalize();
     const {clearLHNCache} = useSidebarOrderedReports();
 
+    const {singleExecution} = useSingleExecution();
+    const waitForNavigate = useWaitForNavigation();
+    const navigateToBiometricsTestPage = singleExecution(
+        waitForNavigate(() => {
+            Navigation.navigate(ROUTES.MULTIFACTOR_AUTHENTICATION_BIOMETRICS_TEST);
+        }),
+    );
+
     // Check if the user is authenticated to show options that require authentication
     const isAuthenticated = useIsAuthenticated();
 
+    // Temporary hardcoded false, expected behavior: status fetched from the MultifactorAuthenticationContext
+    const biometricsTitle = translate('multifactorAuthentication.biometricsTest.troubleshootBiometricsStatus', {registered: false});
+
     return (
         <>
             <Text
@@ -83,6 +99,17 @@ function TestToolMenu() {
                             onPress={clearLHNCache}
                         />
                     </TestToolRow>
+
+                    {/* Allows you to test the Biometrics flow */}
+                    <TestToolRow title={biometricsTitle}>
+                        <View style={[styles.flexRow, styles.gap2]}>
+                            <Button
+                                small
+                                text={translate('multifactorAuthentication.biometricsTest.test')}
+                                onPress={() => navigateToBiometricsTestPage()}
+                            />
+                        </View>
+                    </TestToolRow>
                 </>
             )}
 
diff --git a/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx
index 62fa9a1e17d2..0c8e725f30f0 100644
--- a/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx
+++ b/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx
@@ -10,6 +10,8 @@ import type {AutoCompleteVariant, MagicCodeInputHandle} from '@components/MagicC
 import OfflineWithFeedback from '@components/OfflineWithFeedback';
 import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
 import Text from '@components/Text';
+import ValidateCodeCountdown from '@components/ValidateCodeCountdown';
+import type {ValidateCodeCountdownHandle} from '@components/ValidateCodeCountdown/types';
 import {WideRHPContext} from '@components/WideRHPContextProvider';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
@@ -20,8 +22,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
 import {isMobileSafari} from '@libs/Browser';
 import {getLatestErrorField, getLatestErrorMessage} from '@libs/ErrorUtils';
 import {isValidValidateCode} from '@libs/ValidationUtils';
-import ValidateCodeCountdown from '@pages/signin/ValidateCodeCountdown';
-import type {ValidateCodeCountdownHandle} from '@pages/signin/ValidateCodeCountdown/types';
 import {clearValidateCodeActionError} from '@userActions/User';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
diff --git a/src/pages/signin/ValidateCodeCountdown/index.tsx b/src/components/ValidateCodeCountdown/index.tsx
similarity index 100%
rename from src/pages/signin/ValidateCodeCountdown/index.tsx
rename to src/components/ValidateCodeCountdown/index.tsx
diff --git a/src/pages/signin/ValidateCodeCountdown/types.ts b/src/components/ValidateCodeCountdown/types.ts
similarity index 100%
rename from src/pages/signin/ValidateCodeCountdown/types.ts
rename to src/components/ValidateCodeCountdown/types.ts
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 5041594252a0..7bdfeca882ef 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -17,6 +17,7 @@ import type {
     MergeTransactionNavigatorParamList,
     MissingPersonalDetailsParamList,
     MoneyRequestNavigatorParamList,
+    MultifactorAuthenticationParamList,
     NewChatNavigatorParamList,
     NewReportWorkspaceSelectionNavigatorParamList,
     NewTaskNavigatorParamList,
@@ -984,6 +985,14 @@ const WorkspacesDomainModalStackNavigator = createModalStackNavigator<Workspaces
     [SCREENS.WORKSPACES_DOMAIN_ACCESS_RESTRICTED]: () => require<ReactComponentModule>('../../../../pages/domain/DomainAccessRestrictedPage').default,
 });
 
+const MultifactorAuthenticationStackNavigator = createModalStackNavigator<MultifactorAuthenticationParamList>({
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.MAGIC_CODE]: () => require<ReactComponentModule>('../../../../pages/MultifactorAuthentication/ValidateCodePage').default,
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.BIOMETRICS_TEST]: () => require<ReactComponentModule>('../../../../pages/MultifactorAuthentication/BiometricsTestPage').default,
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.NOTIFICATION]: () => require<ReactComponentModule>('../../../../pages/MultifactorAuthentication/NotificationPage').default,
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.PROMPT]: () => require<ReactComponentModule>('../../../../pages/MultifactorAuthentication/PromptPage').default,
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: () => require<ReactComponentModule>('../../../../pages/ErrorPage/NotFoundPage').default,
+});
+
 export {
     AddPersonalBankAccountModalStackNavigator,
     AddUnreportedExpenseModalStackNavigator,
@@ -1033,4 +1042,5 @@ export {
     WorkspaceConfirmationModalStackNavigator,
     WorkspaceDuplicateModalStackNavigator,
     WorkspacesDomainModalStackNavigator,
+    MultifactorAuthenticationStackNavigator,
 };
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
index 92cbd4148cf2..0b1bf503ee63 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
@@ -400,6 +400,10 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
                             name={SCREENS.RIGHT_MODAL.SEARCH_COLUMNS}
                             component={ModalStackNavigators.SearchColumnsModalStackNavigator}
                         />
+                        <Stack.Screen
+                            name={SCREENS.RIGHT_MODAL.MULTIFACTOR_AUTHENTICATION}
+                            component={ModalStackNavigators.MultifactorAuthenticationStackNavigator}
+                        />
                     </Stack.Navigator>
                 </Animated.View>
                 {/* The third and second overlays are displayed here to cover RHP screens wider than the currently focused screen. */}
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index caf20777d7be..2b8ac2cef4ec 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -1903,6 +1903,15 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                         },
                     },
                 },
+                [SCREENS.RIGHT_MODAL.MULTIFACTOR_AUTHENTICATION]: {
+                    screens: {
+                        [SCREENS.MULTIFACTOR_AUTHENTICATION.MAGIC_CODE]: ROUTES.MULTIFACTOR_AUTHENTICATION_MAGIC_CODE,
+                        [SCREENS.MULTIFACTOR_AUTHENTICATION.BIOMETRICS_TEST]: ROUTES.MULTIFACTOR_AUTHENTICATION_BIOMETRICS_TEST,
+                        [SCREENS.MULTIFACTOR_AUTHENTICATION.NOTIFICATION]: ROUTES.MULTIFACTOR_AUTHENTICATION_NOTIFICATION.route,
+                        [SCREENS.MULTIFACTOR_AUTHENTICATION.PROMPT]: ROUTES.MULTIFACTOR_AUTHENTICATION_PROMPT.route,
+                        [SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: ROUTES.MULTIFACTOR_AUTHENTICATION_NOT_FOUND,
+                    },
+                },
             },
         },
 
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 04fa0a403789..3a6f8cec8c1e 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -2289,6 +2289,7 @@ type RightModalNavigatorParamList = {
     };
     [SCREENS.RIGHT_MODAL.DOMAIN]: NavigatorScreenParams<WorkspacesDomainModalNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.SEARCH_COLUMNS]: NavigatorScreenParams<SearchColumnsParamList>;
+    [SCREENS.RIGHT_MODAL.MULTIFACTOR_AUTHENTICATION]: NavigatorScreenParams<MultifactorAuthenticationParamList>;
 };
 
 type TravelNavigatorParamList = {
@@ -2939,6 +2940,17 @@ type TestToolsModalModalNavigatorParamList = {
     };
 };
 
+type MultifactorAuthenticationParamList = {
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.MAGIC_CODE]: undefined;
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.BIOMETRICS_TEST]: undefined;
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.NOTIFICATION]: {
+        notificationType: ValueOf<typeof CONST.MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE>;
+    };
+    [SCREENS.MULTIFACTOR_AUTHENTICATION.PROMPT]: {
+        promptType: string;
+    };
+};
+
 type RootNavigatorParamList = PublicScreensParamList & AuthScreensParamList & SearchFullscreenNavigatorParamList;
 
 type OnboardingFlowName = keyof OnboardingModalNavigatorParamList;
@@ -3051,4 +3063,5 @@ export type {
     DomainSplitNavigatorParamList,
     DomainScreenName,
     SearchColumnsParamList,
+    MultifactorAuthenticationParamList,
 };
diff --git a/src/pages/MultifactorAuthentication/BiometricsTestPage.tsx b/src/pages/MultifactorAuthentication/BiometricsTestPage.tsx
new file mode 100644
index 000000000000..048703a98ab6
--- /dev/null
+++ b/src/pages/MultifactorAuthentication/BiometricsTestPage.tsx
@@ -0,0 +1,26 @@
+import React, {useEffect} from 'react';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Navigation from '@libs/Navigation/Navigation';
+import ROUTES from '@src/ROUTES';
+
+const LOADING_DELAY_MS = 400;
+
+function MultifactorAuthenticationBiometricsTestPage() {
+    useEffect(() => {
+        // Show a short loading state so the RHP transition feels smooth, then move to the magic code flow
+        const timeoutId = setTimeout(() => Navigation.navigate(ROUTES.MULTIFACTOR_AUTHENTICATION_MAGIC_CODE), LOADING_DELAY_MS);
+
+        return () => clearTimeout(timeoutId);
+    }, []);
+
+    return (
+        <ScreenWrapper testID={MultifactorAuthenticationBiometricsTestPage.displayName}>
+            <FullScreenLoadingIndicator />
+        </ScreenWrapper>
+    );
+}
+
+MultifactorAuthenticationBiometricsTestPage.displayName = 'MultifactorAuthenticationBiometricsTestPage';
+
+export default MultifactorAuthenticationBiometricsTestPage;
diff --git a/src/pages/MultifactorAuthentication/NotificationPage.tsx b/src/pages/MultifactorAuthentication/NotificationPage.tsx
new file mode 100644
index 000000000000..e961ee56c3c8
--- /dev/null
+++ b/src/pages/MultifactorAuthentication/NotificationPage.tsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import {View} from 'react-native';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import Button from '@components/Button';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import {loadIllustration} from '@components/Icon/IllustrationLoader';
+import ScreenWrapper from '@components/ScreenWrapper';
+import {useMemoizedLazyAsset} from '@hooks/useLazyAsset';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {MultifactorAuthenticationParamList} from '@libs/Navigation/types';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import type SCREENS from '@src/SCREENS';
+
+// TODO: this config will be part of the scenario configuration, the current implementation is for testing purposes (https://github.com/Expensify/App/issues/79373)
+const mockedConfigSuccess = {
+    headerTitle: 'multifactorAuthentication.biometricsTest.biometricsTest',
+    title: 'multifactorAuthentication.biometricsTest.authenticationSuccessful',
+    description: 'multifactorAuthentication.biometricsTest.successfullyAuthenticatedUsing',
+} as const satisfies Record<string, TranslationPaths>;
+
+// TODO: this config will be part of the scenario configuration, the current implementation is for testing purposes (https://github.com/Expensify/App/issues/79373)
+const mockedConfigFailure = {
+    headerTitle: 'multifactorAuthentication.biometricsTest.biometricsTest',
+    title: 'multifactorAuthentication.oops',
+    description: 'multifactorAuthentication.biometricsTest.yourAttemptWasUnsuccessful',
+} as const satisfies Record<string, TranslationPaths>;
+
+type MultifactorAuthenticationNotificationPageProps = PlatformStackScreenProps<MultifactorAuthenticationParamList, typeof SCREENS.MULTIFACTOR_AUTHENTICATION.NOTIFICATION>;
+
+function MultifactorAuthenticationNotificationPage({route}: MultifactorAuthenticationNotificationPageProps) {
+    const {translate} = useLocalize();
+    const styles = useThemeStyles();
+    const onGoBackPress = () => {
+        Navigation.dismissModal();
+    };
+
+    const isSuccessNotification = route.params.notificationType === CONST.MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE.SUCCESS;
+
+    let headerTitle = translate(mockedConfigFailure.headerTitle);
+    let title = translate(mockedConfigFailure.title);
+    let description = translate(mockedConfigFailure.description);
+
+    if (isSuccessNotification) {
+        headerTitle = translate(mockedConfigSuccess.headerTitle);
+        title = translate(mockedConfigSuccess.title);
+        // TODO: Replace hardcoded 'FaceID' with the actual authentication type (e.g., 'FaceID', 'TouchID', 'Fingerprint')
+        // once the MFA context provides the auth method used. This will require adding authType to route params and to CONST.
+        description = translate(mockedConfigSuccess.description, {authType: 'FaceID'});
+    }
+
+    const {asset: icon} = useMemoizedLazyAsset(() => loadIllustration(isSuccessNotification ? 'OpenPadlock' : 'HumptyDumpty'));
+
+    return (
+        <ScreenWrapper testID={MultifactorAuthenticationNotificationPage.displayName}>
+            <HeaderWithBackButton
+                title={headerTitle}
+                onBackButtonPress={onGoBackPress}
+                shouldShowBackButton
+            />
+            <View style={styles.flex1}>
+                <BlockingView
+                    icon={icon}
+                    contentFitImage="fill"
+                    iconWidth={isSuccessNotification ? variables.openPadlockWidth : variables.humptyDumptyWidth}
+                    iconHeight={isSuccessNotification ? variables.openPadlockHeight : variables.humptyDumptyHeight}
+                    title={title}
+                    titleStyles={styles.mb2}
+                    subtitle={description}
+                    subtitleStyle={styles.textSupporting}
+                    containerStyle={styles.ph5}
+                    testID={MultifactorAuthenticationNotificationPage.displayName}
+                />
+            </View>
+            <View style={[styles.flexRow, styles.m5, styles.mt0]}>
+                <Button
+                    success
+                    style={styles.flex1}
+                    onPress={onGoBackPress}
+                    text={translate('common.buttonConfirm')}
+                />
+            </View>
+        </ScreenWrapper>
+    );
+}
+
+MultifactorAuthenticationNotificationPage.displayName = 'MultifactorAuthenticationNotificationPage';
+
+export default MultifactorAuthenticationNotificationPage;
diff --git a/src/pages/MultifactorAuthentication/PromptPage.tsx b/src/pages/MultifactorAuthentication/PromptPage.tsx
new file mode 100644
index 000000000000..df649a215be6
--- /dev/null
+++ b/src/pages/MultifactorAuthentication/PromptPage.tsx
@@ -0,0 +1,83 @@
+import React, {useState} from 'react';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import Button from '@components/Button';
+import FixedFooter from '@components/FixedFooter';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import LottieAnimations from '@components/LottieAnimations';
+import MultifactorAuthenticationPromptContent from '@components/MultifactorAuthentication/PromptContent';
+import MultifactorAuthenticationTriggerCancelConfirmModal from '@components/MultifactorAuthentication/TriggerCancelConfirmModal';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@navigation/Navigation';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ROUTES from '@src/ROUTES';
+
+const mockedConfig = {
+    title: 'multifactorAuthentication.verifyYourself.biometrics',
+    subtitle: 'multifactorAuthentication.enableQuickVerification.biometrics',
+} as const satisfies Record<string, TranslationPaths>;
+
+function MultifactorAuthenticationPromptPage() {
+    const {translate} = useLocalize();
+    const styles = useThemeStyles();
+
+    const [isConfirmModalVisible, setConfirmModalVisibility] = useState(false);
+
+    const onConfirm = () => {
+        // Temporary navigation, expected behavior: let the MultifactorAuthentication know that the soft prompt was accepted
+        Navigation.navigate(ROUTES.MULTIFACTOR_AUTHENTICATION_NOTIFICATION.getRoute(CONST.MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE.SUCCESS));
+    };
+
+    const showConfirmModal = () => {
+        setConfirmModalVisibility(true);
+    };
+
+    const hideConfirmModal = () => {
+        setConfirmModalVisibility(false);
+    };
+
+    const cancelFlow = () => {
+        if (!isConfirmModalVisible) {
+            return;
+        }
+
+        hideConfirmModal();
+        // Temporary navigation, expected behavior: trigger the failure from the MultifactorAuthenticationContext
+        Navigation.navigate(ROUTES.MULTIFACTOR_AUTHENTICATION_NOTIFICATION.getRoute(CONST.MULTIFACTOR_AUTHENTICATION_NOTIFICATION_TYPE.FAILURE));
+    };
+
+    return (
+        <ScreenWrapper testID={MultifactorAuthenticationPromptPage.displayName}>
+            <HeaderWithBackButton
+                title={translate('multifactorAuthentication.letsVerifyItsYou')}
+                onBackButtonPress={showConfirmModal}
+                shouldShowBackButton
+            />
+            <FullPageOfflineBlockingView>
+                <MultifactorAuthenticationPromptContent
+                    animation={LottieAnimations.Fingerprint}
+                    title={mockedConfig.title}
+                    subtitle={mockedConfig.subtitle}
+                />
+                <FixedFooter style={[styles.flexColumn, styles.gap3]}>
+                    <Button
+                        success
+                        onPress={onConfirm}
+                        text={translate('common.buttonConfirm')}
+                    />
+                </FixedFooter>
+                <MultifactorAuthenticationTriggerCancelConfirmModal
+                    isVisible={isConfirmModalVisible}
+                    onConfirm={cancelFlow}
+                    onCancel={hideConfirmModal}
+                />
+            </FullPageOfflineBlockingView>
+        </ScreenWrapper>
+    );
+}
+
+MultifactorAuthenticationPromptPage.displayName = 'MultifactorAuthenticationPromptPage';
+
+export default MultifactorAuthenticationPromptPage;
diff --git a/src/pages/MultifactorAuthentication/ValidateCodePage.tsx b/src/pages/MultifactorAuthentication/ValidateCodePage.tsx
new file mode 100644
index 000000000000..ddf857df5c39
--- /dev/null
+++ b/src/pages/MultifactorAuthentication/ValidateCodePage.tsx
@@ -0,0 +1,208 @@
+import React, {useEffect, useRef, useState} from 'react';
+import {View} from 'react-native';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import Button from '@components/Button';
+import FormHelpMessage from '@components/FormHelpMessage';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MagicCodeInput from '@components/MagicCodeInput';
+import type {MagicCodeInputHandle} from '@components/MagicCodeInput';
+import MultifactorAuthenticationValidateCodeResendButton from '@components/MultifactorAuthentication/ValidateCodeResendButton';
+import type {MultifactorAuthenticationValidateCodeResendButtonHandle} from '@components/MultifactorAuthentication/ValidateCodeResendButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useOnyx from '@hooks/useOnyx';
+import useThemeStyles from '@hooks/useThemeStyles';
+import AccountUtils from '@libs/AccountUtils';
+import {getLatestErrorMessage} from '@libs/ErrorUtils';
+import {isValidValidateCode} from '@libs/ValidationUtils';
+import Navigation from '@navigation/Navigation';
+import {clearAccountMessages} from '@userActions/Session';
+import {resendValidateCode} from '@userActions/User';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
+
+type FormError = {
+    inputCode?: TranslationPaths;
+};
+
+function MultifactorAuthenticationValidateCodePage() {
+    const {translate} = useLocalize();
+    const {isOffline} = useNetwork();
+    const styles = useThemeStyles();
+
+    // Onyx data
+    const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true});
+    const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
+
+    const contactMethod = account?.primaryLogin ?? '';
+
+    // Local state
+    const [inputCode, setInputCode] = useState('');
+    const [formError, setFormError] = useState<FormError>({});
+    const [canShowError, setCanShowError] = useState<boolean>(false);
+
+    // Refs
+    const inputRef = useRef<MagicCodeInputHandle>(null);
+    const resendButtonRef = useRef<MultifactorAuthenticationValidateCodeResendButtonHandle>(null);
+    const hasClearedInitialErrorsRef = useRef(false);
+
+    // Derived state
+    const hasError = !!account && !isEmptyObject(account?.errors);
+    const isValidateCodeFormSubmitting = AccountUtils.isValidateCodeFormSubmitting(account);
+    const shouldDisableResendCode = isOffline ?? account?.isLoading;
+
+    // Auto-blur on error
+    useEffect(() => {
+        if (!(inputRef.current && hasError && (session?.autoAuthState === CONST.AUTO_AUTH_STATE.FAILED || account?.isLoading))) {
+            return;
+        }
+        inputRef.current.blur();
+    }, [account?.isLoading, session?.autoAuthState, hasError]);
+
+    // Clear input when code is reset
+    useEffect(() => {
+        if (!inputRef.current || inputCode.length > 0) {
+            return;
+        }
+        inputRef.current.clear();
+    }, [inputCode.length]);
+
+    // Clear any pre-existing errors on mount
+    useEffect(() => {
+        if (hasClearedInitialErrorsRef.current || !account?.errors) {
+            return;
+        }
+        hasClearedInitialErrorsRef.current = true;
+        clearAccountMessages();
+    }, [account?.errors]);
+
+    // Reset formError when hasError changes
+    useEffect(() => {
+        if (!hasError) {
+            return;
+        }
+        setFormError({});
+    }, [hasError]);
+
+    /**
+     * Handle code input and clear formError upon text change
+     */
+    const onCodeInput = (text: string) => {
+        setFormError({});
+        setCanShowError(false);
+        setInputCode(text);
+
+        // Clear backend errors
+        if (account?.errors) {
+            clearAccountMessages();
+        }
+    };
+
+    const resendValidationCode = () => {
+        resendValidateCode(contactMethod);
+        inputRef.current?.clear();
+        setInputCode('');
+        setFormError({});
+        setCanShowError(false);
+        resendButtonRef.current?.resetCountdown();
+    };
+
+    /**
+     * Validate and submit form
+     */
+    const validateAndSubmitForm = () => {
+        // Check if already loading
+        if (account?.isLoading) {
+            return;
+        }
+
+        // Clear backend errors before validation
+        if (account?.errors) {
+            clearAccountMessages();
+        }
+
+        setCanShowError(true);
+
+        // Blur input
+        if (inputRef.current) {
+            inputRef.current.blur();
+        }
+
+        // Validate input
+        if (!inputCode.trim()) {
+            setFormError({inputCode: 'validateCodeForm.error.pleaseFillMagicCode'});
+            return;
+        }
+
+        if (!isValidValidateCode(inputCode)) {
+            setFormError({inputCode: 'validateCodeForm.error.incorrectMagicCode'});
+            return;
+        }
+
+        // Clear errors before submit
+        setFormError({});
+
+        // Temporary navigation, expected behavior: trigger submit from the MultifactorAuthenticationContext
+        // 'enable-biometrics' is a type of the MultifactorAuthentication prompt
+        // will be added as a part of scenario config in another PR to make it complacent with CONSISTENCY-2 (docs)
+        Navigation.navigate(ROUTES.MULTIFACTOR_AUTHENTICATION_PROMPT.getRoute('enable-biometrics'));
+    };
+
+    const onGoBackPress = () => {
+        // Temporary navigation, expected behavior: trigger onBack from the MultifactorAuthenticationContext
+        // Close the RHP instead of returning to the invisible biometrics test screen
+        Navigation.dismissModal();
+    };
+
+    return (
+        <ScreenWrapper testID={MultifactorAuthenticationValidateCodePage.displayName}>
+            <HeaderWithBackButton
+                title={translate('multifactorAuthentication.letsVerifyItsYou')}
+                onBackButtonPress={onGoBackPress}
+                shouldShowBackButton
+            />
+            <FullPageOfflineBlockingView>
+                <Text style={[styles.m5, styles.mt3, styles.textNormal]}>{translate('contacts.enterMagicCode', contactMethod)}</Text>
+                <View style={[styles.mh5]}>
+                    <MagicCodeInput
+                        autoComplete="one-time-code"
+                        name="multifactorAuthenticationValidateCode"
+                        value={inputCode}
+                        onChangeText={onCodeInput}
+                        onFulfill={validateAndSubmitForm}
+                        errorText={canShowError && formError.inputCode ? translate(formError.inputCode) : ''}
+                        hasError={hasError}
+                        ref={inputRef}
+                        maxLength={CONST.MAGIC_CODE_LENGTH}
+                    />
+                    {hasError && <FormHelpMessage message={getLatestErrorMessage(account)} />}
+                    <MultifactorAuthenticationValidateCodeResendButton
+                        ref={resendButtonRef}
+                        shouldDisableResendCode={shouldDisableResendCode}
+                        hasError={hasError}
+                        resendButtonText="validateCodeForm.magicCodeNotReceived"
+                        onResendValidationCode={resendValidationCode}
+                    />
+                </View>
+                <Button
+                    success
+                    large
+                    style={[styles.w100, styles.p5, styles.mtAuto]}
+                    onPress={validateAndSubmitForm}
+                    text={translate('common.verify')}
+                    isLoading={isValidateCodeFormSubmitting}
+                    isDisabled={isOffline}
+                />
+            </FullPageOfflineBlockingView>
+        </ScreenWrapper>
+    );
+}
+
+MultifactorAuthenticationValidateCodePage.displayName = 'MultifactorAuthenticationValidateCodePage';
+
+export default MultifactorAuthenticationValidateCodePage;
diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx
index 86236e1d7155..6e2d73a0f065 100755
--- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx
+++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx
@@ -9,6 +9,8 @@ import MagicCodeInput from '@components/MagicCodeInput';
 import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
 import Text from '@components/Text';
 import TextInput from '@components/TextInput';
+import ValidateCodeCountdown from '@components/ValidateCodeCountdown';
+import type {ValidateCodeCountdownHandle} from '@components/ValidateCodeCountdown/types';
 import type {WithToggleVisibilityViewProps} from '@components/withToggleVisibilityView';
 import withToggleVisibilityView from '@components/withToggleVisibilityView';
 import useLocalize from '@hooks/useLocalize';
@@ -23,8 +25,6 @@ import {getLatestErrorMessage} from '@libs/ErrorUtils';
 import {isValidRecoveryCode, isValidTwoFactorCode, isValidValidateCode} from '@libs/ValidationUtils';
 import ChangeExpensifyLoginLink from '@pages/signin/ChangeExpensifyLoginLink';
 import Terms from '@pages/signin/Terms';
-import ValidateCodeCountdown from '@pages/signin/ValidateCodeCountdown';
-import type {ValidateCodeCountdownHandle} from '@pages/signin/ValidateCodeCountdown/types';
 import {clearAccountMessages, clearSignInData as sessionActionsClearSignInData, signIn, signInWithValidateCode} from '@userActions/Session';
 import {resendValidateCode as userActionsResendValidateCode} from '@userActions/User';
 import CONST from '@src/CONST';
diff --git a/src/styles/index.ts b/src/styles/index.ts
index 7506658f0865..e8f94330d33d 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -3292,6 +3292,11 @@ const staticStyles = (theme: ThemeColors) =>
             height: 180,
         },
 
+        mfaBlockingViewAnimation: {
+            width: 180,
+            height: 180,
+        },
+
         locationErrorLinkText: {
             textAlignVertical: 'center',
             fontSize: variables.fontSizeLabel,
diff --git a/tests/unit/NetworkTest.tsx b/tests/unit/NetworkTest.tsx
index deb12fce73d9..d254e0bf2549 100644
--- a/tests/unit/NetworkTest.tsx
+++ b/tests/unit/NetworkTest.tsx
@@ -1,5 +1,6 @@
 import NetInfo from '@react-native-community/netinfo';
 import type {NetInfoState} from '@react-native-community/netinfo';
+import {NavigationContainer} from '@react-navigation/native';
 import {fireEvent, render, screen, waitFor} from '@testing-library/react-native';
 import {sub as dateSubtract} from 'date-fns/sub';
 import type {Mock} from 'jest-mock';
@@ -8,6 +9,7 @@ import MockedOnyx from 'react-native-onyx';
 import TestToolMenu from '@components/TestToolMenu';
 import {confirmReadyToOpenApp, reconnectApp} from '@libs/actions/App';
 import {resetReauthentication} from '@libs/Middleware/Reauthentication';
+import navigationRef from '@libs/Navigation/navigationRef';
 import CONST from '@src/CONST';
 import * as NetworkActions from '@src/libs/actions/Network';
 import OnyxUpdateManager from '@src/libs/actions/OnyxUpdateManager';
@@ -480,7 +482,16 @@ describe('NetworkTests', () => {
         const setShouldFailAllRequestsSpy = jest.spyOn(NetworkActions, 'setShouldFailAllRequests');
 
         // Given an opened test tool menu
-        render(<TestToolMenu />);
+        render(
+            <NavigationContainer
+                ref={navigationRef}
+                onReady={() => {
+                    // Navigation is ready, but we still need to handle the timing issue
+                }}
+            >
+                <TestToolMenu />
+            </NavigationContainer>,
+        );
         expect(screen.getByAccessibilityHint('Force offline')).not.toBeDisabled();
         expect(screen.getByAccessibilityHint('Simulate failing network requests')).not.toBeDisabled();
 
