From 1989e99f17539ff3bfbad7e06d007ab84ba8770c Mon Sep 17 00:00:00 2001
From: Bernhard Owen Josephus <bernhard.josephus@gmail.com>
Date: Thu, 19 Dec 2024 16:32:38 +0800
Subject: [PATCH 1/2] fix blank screen when using invalid code and there is an
 exitTo param

---
 .../BlockingViews/FullPageNotFoundView.tsx    |  9 +++-
 .../ValidateCode/ValidateCodeModal.tsx        |  6 ++-
 src/pages/ValidateLoginPage/index.website.tsx |  9 ++--
 tests/ui/ValidateLoginPageTest.tsx            | 54 +++++++++++++++++++
 4 files changed, 70 insertions(+), 8 deletions(-)
 create mode 100644 tests/ui/ValidateLoginPageTest.tsx

diff --git a/src/components/BlockingViews/FullPageNotFoundView.tsx b/src/components/BlockingViews/FullPageNotFoundView.tsx
index 029b79b432cf..ad1a659e6d9f 100644
--- a/src/components/BlockingViews/FullPageNotFoundView.tsx
+++ b/src/components/BlockingViews/FullPageNotFoundView.tsx
@@ -11,6 +11,9 @@ import BlockingView from './BlockingView';
 import ForceFullScreenView from './ForceFullScreenView';
 
 type FullPageNotFoundViewProps = {
+    /** TestID for test */
+    testID?: string;
+
     /** Child elements */
     children?: React.ReactNode;
 
@@ -44,6 +47,7 @@ type FullPageNotFoundViewProps = {
 
 // eslint-disable-next-line rulesdir/no-negated-variables
 function FullPageNotFoundView({
+    testID,
     children = null,
     shouldShow = false,
     titleKey = 'notFound.notHere',
@@ -65,7 +69,10 @@ function FullPageNotFoundView({
                     onBackButtonPress={onBackButtonPress}
                     shouldShowBackButton={shouldShowBackButton}
                 />
-                <View style={[styles.flex1, styles.blockingViewContainer]}>
+                <View
+                    style={[styles.flex1, styles.blockingViewContainer]}
+                    testID={testID}
+                >
                     <BlockingView
                         icon={Illustrations.ToddBehindCloud}
                         iconWidth={variables.modalTopIconWidth}
diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx
index 089416267b32..46da67e4a2b8 100644
--- a/src/components/ValidateCode/ValidateCodeModal.tsx
+++ b/src/components/ValidateCode/ValidateCodeModal.tsx
@@ -34,13 +34,17 @@ function ValidateCodeModal({code, accountID}: ValidateCodeModalProps) {
 
     return (
         <FullPageNotFoundView
+            testID="validate-code-not-found"
             shouldShow={!ValidationUtils.isValidValidateCode(code)}
             shouldShowBackButton={shouldUseNarrowLayout}
             onLinkPress={() => {
                 Navigation.goBack();
             }}
         >
-            <View style={styles.deeplinkWrapperContainer}>
+            <View
+                style={styles.deeplinkWrapperContainer}
+                testID="validate-code"
+            >
                 <View style={styles.deeplinkWrapperMessage}>
                     <View style={styles.mb2}>
                         <Icon
diff --git a/src/pages/ValidateLoginPage/index.website.tsx b/src/pages/ValidateLoginPage/index.website.tsx
index 2d1af21ceeab..af4c02f2671d 100644
--- a/src/pages/ValidateLoginPage/index.website.tsx
+++ b/src/pages/ValidateLoginPage/index.website.tsx
@@ -30,7 +30,8 @@ function ValidateLoginPage({
     const is2FARequired = !!account?.requiresTwoFactorAuth;
     const cachedAccountID = credentials?.accountID;
     const isUserClickedSignIn = !login && isSignedIn && (autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.SIGNING_IN || autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.JUST_SIGNED_IN);
-    const shouldStartSignInWithValidateCode = !isUserClickedSignIn && !isSignedIn && (!!login || !!exitTo);
+    const shouldStartSignInWithValidateCode = !isUserClickedSignIn && !isSignedIn && (!!login || !!exitTo) && ValidationUtils.isValidValidateCode(validateCode);
+    const isNavigatingToExitTo = isSignedIn && !!exitTo;
 
     useEffect(() => {
         if (isUserClickedSignIn) {
@@ -49,10 +50,6 @@ function ValidateLoginPage({
             return;
         }
 
-        if (!ValidationUtils.isValidValidateCode(validateCode)) {
-            return;
-        }
-
         // The user has initiated the sign in process on the same browser, in another tab.
         Session.signInWithValidateCode(Number(accountID), validateCode);
 
@@ -83,7 +80,7 @@ function ValidateLoginPage({
             {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.JUST_SIGNED_IN && is2FARequired && !isSignedIn && !!login && <JustSignedInModal is2FARequired />}
             {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.JUST_SIGNED_IN && isSignedIn && !exitTo && !!login && <JustSignedInModal is2FARequired={false} />}
             {/* If session.autoAuthState isn't available yet, we use shouldStartSignInWithValidateCode to conditionally render the component instead of local autoAuthState which contains a default value of NOT_STARTED */}
-            {(!autoAuthState ? !shouldStartSignInWithValidateCode : autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.NOT_STARTED) && !exitTo && (
+            {(!autoAuthState ? !shouldStartSignInWithValidateCode : autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.NOT_STARTED && !isNavigatingToExitTo) && (
                 <ValidateCodeModal
                     accountID={Number(accountID)}
                     code={validateCode}
diff --git a/tests/ui/ValidateLoginPageTest.tsx b/tests/ui/ValidateLoginPageTest.tsx
new file mode 100644
index 000000000000..24276af3f454
--- /dev/null
+++ b/tests/ui/ValidateLoginPageTest.tsx
@@ -0,0 +1,54 @@
+import {NavigationContainer} from '@react-navigation/native';
+import {render, screen} from '@testing-library/react-native';
+import React from 'react';
+import Onyx from 'react-native-onyx';
+import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator';
+import {PublicScreensParamList} from '@libs/Navigation/types';
+import ValidateLoginPage from '@pages/ValidateLoginPage/index.website';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import SCREENS from '@src/SCREENS';
+
+const RootStack = createResponsiveStackNavigator<PublicScreensParamList>();
+
+const renderPage = (initialParams: PublicScreensParamList[typeof SCREENS.VALIDATE_LOGIN]) => {
+    return render(
+        <NavigationContainer>
+            <RootStack.Navigator>
+                <RootStack.Screen
+                    name={SCREENS.VALIDATE_LOGIN}
+                    component={ValidateLoginPage}
+                    initialParams={initialParams}
+                />
+            </RootStack.Navigator>
+        </NavigationContainer>,
+    );
+};
+
+describe('ValidateLoginPage', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+        Onyx.clear();
+    });
+
+    it('Should show not found view when the magic code is invalid and there is an exitTo param', async () => {
+        await Onyx.set(ONYXKEYS.SESSION, {
+            autoAuthState: CONST.AUTO_AUTH_STATE.NOT_STARTED,
+        });
+
+        renderPage({accountID: '1', validateCode: 'ABCDEF', exitTo: 'concierge'});
+
+        expect(screen.queryByTestId('validate-code-not-found')).not.toBeNull();
+    });
+
+    it('Should not show ValidateCodeModal when signed in and there is an exitTo param', async () => {
+        await Onyx.set(ONYXKEYS.SESSION, {
+            authToken: 'abcd',
+            autoAuthState: CONST.AUTO_AUTH_STATE.NOT_STARTED,
+        });
+
+        renderPage({accountID: '1', validateCode: '123456', exitTo: 'concierge'});
+
+        expect(screen.queryByTestId('validate-code')).toBeNull();
+    });
+});

From e2de781472a78adaf7fa48025813b0f66910cd3c Mon Sep 17 00:00:00 2001
From: Bernhard Owen Josephus <bernhard.josephus@gmail.com>
Date: Thu, 19 Dec 2024 16:39:16 +0800
Subject: [PATCH 2/2] lint

---
 tests/ui/ValidateLoginPageTest.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/ui/ValidateLoginPageTest.tsx b/tests/ui/ValidateLoginPageTest.tsx
index 24276af3f454..19a9a375d726 100644
--- a/tests/ui/ValidateLoginPageTest.tsx
+++ b/tests/ui/ValidateLoginPageTest.tsx
@@ -3,7 +3,7 @@ import {render, screen} from '@testing-library/react-native';
 import React from 'react';
 import Onyx from 'react-native-onyx';
 import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator';
-import {PublicScreensParamList} from '@libs/Navigation/types';
+import type {PublicScreensParamList} from '@libs/Navigation/types';
 import ValidateLoginPage from '@pages/ValidateLoginPage/index.website';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
@@ -38,7 +38,7 @@ describe('ValidateLoginPage', () => {
 
         renderPage({accountID: '1', validateCode: 'ABCDEF', exitTo: 'concierge'});
 
-        expect(screen.queryByTestId('validate-code-not-found')).not.toBeNull();
+        expect(screen.getByTestId('validate-code-not-found')).not.toBeNull();
     });
 
     it('Should not show ValidateCodeModal when signed in and there is an exitTo param', async () => {
