diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx
index 372d71c8b0d0..b9b2c186b82d 100644
--- a/src/components/SettlementButton/index.tsx
+++ b/src/components/SettlementButton/index.tsx
@@ -20,12 +20,12 @@ import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
-import useVerifyAccountAndResume from '@hooks/useVerifyAccountAndResume';
import {createWorkspace, generateDefaultWorkspaceName, isCurrencySupportedForDirectReimbursement, isCurrencySupportedForGlobalReimbursement} from '@libs/actions/Policy/Policy';
import {navigateToBankAccountRoute} from '@libs/actions/ReimbursementAccount';
import {getLastPolicyBankAccountID, getLastPolicyPaymentMethod} from '@libs/actions/Search';
import {isBankAccountPartiallySetup} from '@libs/BankAccountUtils';
+import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
import Navigation from '@libs/Navigation/Navigation';
import {isTrackOnboardingChoice} from '@libs/OnboardingUtils';
import {formatPaymentMethods, getActivePaymentType, getBusinessBankAccountOptions, matchesCurrency} from '@libs/PaymentUtils';
@@ -50,7 +50,7 @@ import {navigateToConciergeChat} from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
+import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES';
import type {AccountData, BankAccount, LastPaymentMethodType, Policy} from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -58,11 +58,11 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {GestureResponderEvent} from 'react-native';
import type {TupleToUnion} from 'type-fest';
-import {delegateEmailSelector} from '@selectors/Account';
+import {delegateEmailSelector, isUserValidatedSelector} from '@selectors/Account';
import {hasSeenTourSelector} from '@selectors/Onboarding';
import {personalDetailsLoginSelector} from '@selectors/PersonalDetails';
import truncate from 'lodash/truncate';
-import React, {useContext} from 'react';
+import React, {useCallback, useContext} from 'react';
import {View} from 'react-native';
import type SettlementButtonProps from './types';
@@ -127,6 +127,7 @@ function SettlementButton({
const [conciergeReportID = ''] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const [iouReportNextStep] = useOnyx(`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}`);
const [ownerLogin] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsLoginSelector(iouReport?.ownerAccountID)});
+ const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector});
const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED);
const policyEmployeeAccountIDs = getPolicyEmployeeAccountIDs(policy, accountID);
const reportBelongsToWorkspace = policyID ? doesReportBelongToWorkspace(chatReport, policyEmployeeAccountIDs, policyID, conciergeReportID) : false;
@@ -199,73 +200,76 @@ function SettlementButton({
return formattedPaymentMethods.filter((ba) => (ba.accountData as AccountData)?.type === CONST.BANK_ACCOUNT.TYPE.PERSONAL);
}
- // The guards checked after the account-validation gate. Also re-checked when a payment
- // interrupted by account validation resumes, since the validation gate skipped them.
- const checkForPostValidationBlockers = () => {
- if (isBankAccountLocked) {
- showConfirmModal({
- title: translate('bankAccount.lockedBankAccount'),
- prompt: (
-
-
-
- ),
- confirmText: translate('bankAccount.unlockBankAccount'),
- cancelText: translate('common.cancel'),
- }).then(({action}) => {
- if (action !== ModalActions.CONFIRM) {
- return;
- }
- if (policy?.achAccount?.bankAccountID === undefined) {
- return;
- }
- pressLockedBankAccount(policy?.achAccount?.bankAccountID, translate, conciergeReportID, delegateAccountID);
- navigateToConciergeChat(conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas);
- });
- return true;
- }
-
- if (policy && shouldRestrictUserBillableActions(policy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed, currentUserAccountID)) {
- Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id));
- return true;
- }
-
- return false;
- };
-
- const {isUserValidated, verifyAccountAndResume} = useVerifyAccountAndResume((retry?: () => void) => {
- // The validation gate returned before these guards could run, so apply them to the resumed.
- if (checkForPostValidationBlockers()) {
- return;
- }
- retry?.();
- });
+ const checkForNecessaryAction = useCallback(
+ (paymentMethodType?: PaymentMethodType) => {
+ if (isDelegateAccessRestricted) {
+ showDelegateNoAccessModal();
+ return true;
+ }
- const checkForNecessaryAction = (paymentMethodType?: PaymentMethodType, retry?: () => void) => {
- if (isDelegateAccessRestricted) {
- showDelegateNoAccessModal();
- return true;
- }
+ if (isAccountLocked) {
+ showLockedAccountModal();
+ return true;
+ }
- if (isAccountLocked) {
- showLockedAccountModal();
- return true;
- }
+ if (!isUserValidated && paymentMethodType !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
+ Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.VERIFY_ACCOUNT.path));
+ return true;
+ }
- if (!isUserValidated && paymentMethodType !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
- verifyAccountAndResume(retry);
- return true;
- }
+ if (isBankAccountLocked) {
+ showConfirmModal({
+ title: translate('bankAccount.lockedBankAccount'),
+ prompt: (
+
+
+
+ ),
+ confirmText: translate('bankAccount.unlockBankAccount'),
+ cancelText: translate('common.cancel'),
+ }).then(({action}) => {
+ if (action !== ModalActions.CONFIRM) {
+ return;
+ }
+ if (policy?.achAccount?.bankAccountID === undefined) {
+ return;
+ }
+ pressLockedBankAccount(policy?.achAccount?.bankAccountID, translate, conciergeReportID, delegateAccountID);
+ navigateToConciergeChat(conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas);
+ });
+ return true;
+ }
- return checkForPostValidationBlockers();
- };
+ if (policy && shouldRestrictUserBillableActions(policy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed, currentUserAccountID)) {
+ Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id));
+ return true;
+ }
- const runPaymentAction = (paymentMethodType: PaymentMethodType | undefined, action: () => void) => {
- if (checkForNecessaryAction(paymentMethodType, action)) {
- return;
- }
- action();
- };
+ return false;
+ },
+ [
+ isDelegateAccessRestricted,
+ isAccountLocked,
+ isUserValidated,
+ isBankAccountLocked,
+ policy,
+ userBillingGracePeriodEnds,
+ ownerBillingGracePeriodEnd,
+ showDelegateNoAccessModal,
+ showLockedAccountModal,
+ showConfirmModal,
+ translate,
+ styles.renderHTML,
+ styles.flexRow,
+ conciergeReportID,
+ introSelected,
+ currentUserAccountID,
+ isSelfTourViewed,
+ betas,
+ amountOwed,
+ delegateAccountID,
+ ],
+ );
const shortFormPayElsewhereButton = {
text: translate('iou.pay'),
@@ -336,15 +340,17 @@ function SettlementButton({
value: CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT,
description: account.description,
shouldIgnoreCompactStyle: true,
- onSelected: () =>
- runPaymentAction(CONST.IOU.PAYMENT_TYPE.VBBA, () =>
- onPress({
- paymentType: CONST.IOU.PAYMENT_TYPE.VBBA,
- payAsBusiness: true,
- methodID: account.methodID,
- paymentMethod: CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT,
- }),
- ),
+ onSelected: () => {
+ if (checkForNecessaryAction(CONST.IOU.PAYMENT_TYPE.VBBA)) {
+ return;
+ }
+ onPress({
+ paymentType: CONST.IOU.PAYMENT_TYPE.VBBA,
+ payAsBusiness: true,
+ methodID: account.methodID,
+ paymentMethod: CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT,
+ });
+ },
});
}
}
@@ -397,15 +403,17 @@ function SettlementButton({
description: formattedPaymentMethod?.description ?? '',
icon: formattedPaymentMethod?.icon,
shouldUpdateSelectedIndex: true,
- onSelected: () =>
- runPaymentAction(CONST.IOU.PAYMENT_TYPE.EXPENSIFY, () =>
- onPress({
- paymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY,
- payAsBusiness,
- methodID: formattedPaymentMethod.methodID,
- paymentMethod: formattedPaymentMethod.accountType,
- }),
- ),
+ onSelected: () => {
+ if (checkForNecessaryAction(CONST.IOU.PAYMENT_TYPE.EXPENSIFY)) {
+ return;
+ }
+ onPress({
+ paymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY,
+ payAsBusiness,
+ methodID: formattedPaymentMethod.methodID,
+ paymentMethod: formattedPaymentMethod.accountType,
+ });
+ },
iconStyles: formattedPaymentMethod?.iconStyles,
iconHeight: formattedPaymentMethod?.iconSize,
iconWidth: formattedPaymentMethod?.iconSize,
@@ -457,7 +465,12 @@ function SettlementButton({
icon: icons.Cash,
value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE,
shouldUpdateSelectedIndex: true,
- onSelected: () => runPaymentAction(CONST.IOU.PAYMENT_TYPE.ELSEWHERE, () => onPress({paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, payAsBusiness})),
+ onSelected: () => {
+ if (checkForNecessaryAction(CONST.IOU.PAYMENT_TYPE.ELSEWHERE)) {
+ return;
+ }
+ onPress({paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, payAsBusiness});
+ },
},
];
};
@@ -564,8 +577,17 @@ function SettlementButton({
});
};
- const executePaymentSelection = (event: KYCFlowEvent, selectedOption: string, triggerKYCFlow: TriggerKYCFlow, activePaymentType: ReturnType) => {
- const {paymentType, policyFromPaymentMethod, policyFromContext, shouldSelectPaymentMethod} = activePaymentType;
+ const handlePaymentSelection = (event: GestureResponderEvent | KeyboardEvent | undefined, selectedOption: string, triggerKYCFlow: (params: ContinueActionParams) => void) => {
+ const {paymentType, policyFromPaymentMethod, policyFromContext, shouldSelectPaymentMethod} = getActivePaymentType(
+ selectedOption,
+ activeAdminPolicies,
+ businessBankAccountOptions,
+ policyIDKey,
+ );
+
+ if (checkForNecessaryAction(paymentType)) {
+ return;
+ }
const isPayingWithMethod = paymentType !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE;
if ((!!policyFromPaymentMethod || shouldSelectPaymentMethod) && (isPayingWithMethod || !!policyFromPaymentMethod)) {
@@ -576,12 +598,6 @@ function SettlementButton({
selectPaymentType(event, selectedOption as PaymentMethodType);
};
- const handlePaymentSelection = (event: KYCFlowEvent, selectedOption: string, triggerKYCFlow: TriggerKYCFlow) => {
- const activePaymentType = getActivePaymentType(selectedOption, activeAdminPolicies, businessBankAccountOptions, policyIDKey);
-
- runPaymentAction(activePaymentType.paymentType, () => executePaymentSelection(event, selectedOption, triggerKYCFlow, activePaymentType));
- };
-
let customText: string;
if (shouldUseShortForm) {
customText = translate('iou.pay');
diff --git a/src/components/WideRHPContextProvider/useShouldRenderOverlay.ts b/src/components/WideRHPContextProvider/useShouldRenderOverlay.ts
index 0e89add7693e..a4126f182f74 100644
--- a/src/components/WideRHPContextProvider/useShouldRenderOverlay.ts
+++ b/src/components/WideRHPContextProvider/useShouldRenderOverlay.ts
@@ -22,13 +22,7 @@ function useShouldRenderOverlay(condition: boolean, overlayProgress: Animated.Va
toValue: 0,
duration: OVERLAY_TIMING_DURATION,
useNativeDriver: false,
- }).start(({finished}) => {
- // When the hide animation is interrupted by a new show animation (the condition flipped back to true
- // before the animation completed), this callback still fires with finished=false. Setting the state
- // to false in that case would permanently hide the overlay that should be visible.
- if (!finished) {
- return;
- }
+ }).start(() => {
setShouldRenderOverlay(false);
});
}
diff --git a/src/hooks/useVerifyAccountAndResume.ts b/src/hooks/useVerifyAccountAndResume.ts
deleted file mode 100644
index 4c662e6c25d2..000000000000
--- a/src/hooks/useVerifyAccountAndResume.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
-import splitPathAndQuery from '@libs/Navigation/helpers/dynamicRoutesUtils/splitPathAndQuery';
-import Navigation from '@libs/Navigation/Navigation';
-import navigationRef from '@libs/Navigation/navigationRef';
-
-import ONYXKEYS from '@src/ONYXKEYS';
-import {DYNAMIC_ROUTES} from '@src/ROUTES';
-
-import {isUserValidatedSelector} from '@selectors/Account';
-import {useEffect, useEffectEvent, useState} from 'react';
-
-import useOnyx from './useOnyx';
-
-/**
- * Returns a trigger that sends an unvalidated user to the verify-account (magic code) screen and,
- * once they validate there, calls `onResume` with the payload the trigger stored.
- */
-function useVerifyAccountAndResume(onResume: (payload: TPayload) => void) {
- const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector});
- const [pendingAction, setPendingAction] = useState<{payload: TPayload; verifyAccountPath: string} | null>(null);
-
- // Effect event, so the resume runs the latest `onResume` (a press-time closure would see pre-validation state).
- const resumeAction = useEffectEvent(onResume);
-
- // Effect event, so the listener reads the freshest validation state and doesn't mistake the success-driven close of the verify-account page for an abandon.
- const handleNavigationStateChange = useEffectEvent(() => {
- if (!pendingAction || isUserValidated || Navigation.getActiveRouteWithoutParams() === pendingAction.verifyAccountPath) {
- return;
- }
- setPendingAction(null);
- });
-
- useEffect(() => {
- if (!pendingAction) {
- return;
- }
-
- // Leaving the verify-account screen without validating abandons the action, which is what makes resuming below safe without a route check.
- if (!isUserValidated) {
- return navigationRef.addListener('state', handleNavigationStateChange);
- }
-
- // Validation succeeded — resume even if the verify-account page already dismissed itself.
- const isVerifyAccountScreenStillOpen = Navigation.getActiveRouteWithoutParams() === pendingAction.verifyAccountPath;
- const resume = () => {
- setPendingAction(null);
- resumeAction(pendingAction.payload);
- };
- // While the page is still open its closing transition hasn't been dispatched yet, so wait for the upcoming one; otherwise the close is already in flight (or done), so only wait out active transitions.
- const handle = isVerifyAccountScreenStillOpen ? Navigation.runAfterUpcomingTransition(resume) : Navigation.runAfterTransition(resume);
-
- return () => handle.cancel();
- }, [isUserValidated, pendingAction]);
-
- const verifyAccountAndResume = (payload: TPayload) => {
- const verifyAccountRoute = createDynamicRoute(DYNAMIC_ROUTES.VERIFY_ACCOUNT.path);
- const [verifyAccountPath] = splitPathAndQuery(verifyAccountRoute);
- setPendingAction(verifyAccountPath ? {payload, verifyAccountPath} : null);
- Navigation.navigate(verifyAccountRoute);
- };
-
- return {isUserValidated, verifyAccountAndResume};
-}
-
-export default useVerifyAccountAndResume;
diff --git a/tests/ui/components/SettlementButtonTest.tsx b/tests/ui/components/SettlementButtonTest.tsx
index 36ed0c2fd83f..1aa37a0189f0 100644
--- a/tests/ui/components/SettlementButtonTest.tsx
+++ b/tests/ui/components/SettlementButtonTest.tsx
@@ -81,16 +81,6 @@ jest.mock('@libs/actions/Policy/Policy', () => ({
createWorkspace: jest.fn(() => ({policyID: 'mock-created-policy-id'})),
}));
-const mockVerifyAccountAndResume = jest.fn();
-
-jest.mock('@hooks/useVerifyAccountAndResume', () => ({
- __esModule: true,
- default: jest.fn(() => ({
- isUserValidated: true,
- verifyAccountAndResume: mockVerifyAccountAndResume,
- })),
-}));
-
const ACCOUNT_ID = 1;
const ACCOUNT_LOGIN = 'test@user.com';
const REPORT_ID = '100';
diff --git a/tests/unit/hooks/useVerifyAccountAndResume.test.ts b/tests/unit/hooks/useVerifyAccountAndResume.test.ts
deleted file mode 100644
index 5a11d9e00e0e..000000000000
--- a/tests/unit/hooks/useVerifyAccountAndResume.test.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-import {act, renderHook, waitFor} from '@testing-library/react-native';
-
-import useVerifyAccountAndResume from '@hooks/useVerifyAccountAndResume';
-
-import Navigation from '@libs/Navigation/Navigation';
-import navigationRef from '@libs/Navigation/navigationRef';
-
-import ONYXKEYS from '@src/ONYXKEYS';
-
-import Onyx from 'react-native-onyx';
-
-import waitForBatchedUpdatesWithAct from '../../utils/waitForBatchedUpdatesWithAct';
-
-type ResumePayload = {
- paymentID: string;
-};
-
-const mockVerifyAccountRoute = 'r/123/verify-account?source=pay';
-const mockVerifyAccountPath = 'r/123/verify-account';
-const mockCancelTransition = jest.fn();
-const mockNavigationStateListeners = new Set<() => void>();
-let mockPendingTransitionCallbacks: Array<() => void> = [];
-
-jest.mock('@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute', () => ({
- __esModule: true,
- default: jest.fn(() => 'r/123/verify-account?source=pay'),
-}));
-
-jest.mock('@libs/Navigation/Navigation', () => {
- const mockNavigationModule = {
- navigate: jest.fn(),
- runAfterTransition: jest.fn(),
- runAfterUpcomingTransition: jest.fn(),
- getActiveRouteWithoutParams: jest.fn(),
- };
- return {
- __esModule: true,
- default: mockNavigationModule,
- ...mockNavigationModule,
- };
-});
-
-jest.mock('@libs/Navigation/navigationRef', () => ({
- __esModule: true,
- default: {
- addListener: jest.fn(),
- },
-}));
-
-const mockedNavigation = jest.mocked(Navigation);
-const mockedNavigationRef = jest.mocked(navigationRef);
-
-function emitNavigationStateChange() {
- for (const listener of mockNavigationStateListeners) {
- listener();
- }
-}
-
-async function setIsUserValidated(validated: boolean) {
- await act(async () => {
- await Onyx.merge(ONYXKEYS.ACCOUNT, {validated});
- });
- await waitForBatchedUpdatesWithAct();
-}
-
-async function clearOnyx() {
- await act(async () => {
- await Onyx.clear();
- });
- await waitForBatchedUpdatesWithAct();
-}
-
-describe('useVerifyAccountAndResume', () => {
- beforeAll(() => {
- Onyx.init({keys: ONYXKEYS});
- });
-
- beforeEach(async () => {
- await clearOnyx();
-
- jest.clearAllMocks();
- mockNavigationStateListeners.clear();
- mockPendingTransitionCallbacks = [];
- mockedNavigation.getActiveRouteWithoutParams.mockReturnValue(mockVerifyAccountPath);
- mockedNavigation.runAfterTransition.mockImplementation((callback: () => void) => {
- mockPendingTransitionCallbacks.push(callback);
- return {cancel: mockCancelTransition};
- });
- mockedNavigation.runAfterUpcomingTransition.mockImplementation((callback: () => void) => {
- mockPendingTransitionCallbacks.push(callback);
- return {cancel: mockCancelTransition};
- });
- mockedNavigationRef.addListener.mockImplementation((_eventName, listener) => {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
- const stateListener = listener as () => void;
- mockNavigationStateListeners.add(stateListener);
- return () => {
- mockNavigationStateListeners.delete(stateListener);
- };
- });
-
- await setIsUserValidated(false);
- });
-
- afterEach(async () => {
- await clearOnyx();
- });
-
- it('navigates to verify account and exposes validation state', async () => {
- const onResume = jest.fn();
- const {result} = renderHook(() => useVerifyAccountAndResume(onResume));
-
- await waitFor(() => {
- expect(result.current.isUserValidated).toBe(false);
- });
-
- act(() => {
- result.current.verifyAccountAndResume({paymentID: 'payment-1'});
- });
-
- expect(mockedNavigation.navigate).toHaveBeenCalledWith(mockVerifyAccountRoute);
- expect(onResume).not.toHaveBeenCalled();
- });
-
- it('resumes the stored payload after validation on the same verify account route', async () => {
- const initialOnResume = jest.fn();
- const latestOnResume = jest.fn();
- const {result, rerender} = renderHook(({onResume}: {onResume: (payload: ResumePayload) => void}) => useVerifyAccountAndResume(onResume), {
- initialProps: {onResume: initialOnResume},
- });
-
- act(() => {
- result.current.verifyAccountAndResume({paymentID: 'payment-1'});
- });
- rerender({onResume: latestOnResume});
-
- await setIsUserValidated(true);
-
- await waitFor(() => {
- expect(mockedNavigation.runAfterUpcomingTransition).toHaveBeenCalledTimes(1);
- });
- expect(latestOnResume).not.toHaveBeenCalled();
-
- act(() => {
- mockPendingTransitionCallbacks.at(0)?.();
- });
-
- expect(initialOnResume).not.toHaveBeenCalled();
- expect(latestOnResume).toHaveBeenCalledWith({paymentID: 'payment-1'});
- });
-
- it('resumes when the verify account route already closed itself before validation was observed', async () => {
- const onResume = jest.fn();
- const {result} = renderHook(() => useVerifyAccountAndResume(onResume));
-
- act(() => {
- result.current.verifyAccountAndResume({paymentID: 'payment-1'});
- });
-
- // The verify page's success effect navigates back as soon as validation succeeds, so by the time
- // this hook observes the validated state the active route is already the originating screen.
- mockedNavigation.getActiveRouteWithoutParams.mockReturnValue('r/123');
- await setIsUserValidated(true);
-
- await waitFor(() => {
- expect(mockedNavigation.runAfterTransition).toHaveBeenCalledTimes(1);
- });
- expect(mockedNavigation.runAfterUpcomingTransition).not.toHaveBeenCalled();
-
- act(() => {
- mockPendingTransitionCallbacks.at(0)?.();
- });
-
- expect(onResume).toHaveBeenCalledWith({paymentID: 'payment-1'});
- });
-
- it('drops the pending resume when the user leaves the verify account route before validation', async () => {
- const onResume = jest.fn();
- const {result} = renderHook(() => useVerifyAccountAndResume(onResume));
-
- act(() => {
- result.current.verifyAccountAndResume({paymentID: 'payment-1'});
- });
-
- await waitFor(() => {
- expect(mockNavigationStateListeners.size).toBe(1);
- });
-
- mockedNavigation.getActiveRouteWithoutParams.mockReturnValue('r/123');
- act(() => {
- emitNavigationStateChange();
- });
-
- mockedNavigation.getActiveRouteWithoutParams.mockReturnValue(mockVerifyAccountPath);
- await setIsUserValidated(true);
-
- expect(mockedNavigation.runAfterUpcomingTransition).not.toHaveBeenCalled();
- expect(onResume).not.toHaveBeenCalled();
- });
-});