Skip to content

Commit 449b88c

Browse files
authored
Merge pull request #90166 from mukhrr/fix/90037
[CP Staging] fixed crash on IOU split distance RHP back button navigation
2 parents 33f5a83 + dcc2339 commit 449b88c

2 files changed

Lines changed: 100 additions & 7 deletions

File tree

src/pages/iou/request/step/IOURequestStepDistance.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -356,15 +356,17 @@ function IOURequestStepDistance({
356356
if (isEditingSplit) {
357357
iouWaypointType = CONST.IOU.TYPE.SPLIT_EXPENSE;
358358
}
359-
// Construct the backTo URL explicitly to match the stack entry created when we navigated
360-
// to this distance edit page. Using Navigation.getActiveRoute() would return a URL with
361-
// the OnyxTabNavigator's tab suffix (e.g. "/distance-map") which doesn't match the stack
362-
// entry — causing Navigation.goBack() to REPLACE instead of POP and creating a duplicate
363-
// distance page entry in the stack.
364-
const waypointBackTo = ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(action, iouType, transactionID, report?.reportID ?? reportID, backTo);
359+
// In the edit flow this page is wrapped in an OnyxTabNavigator, so Navigation.getActiveRoute()
360+
// returns a URL with the tab suffix (e.g. "/distance-map") that doesn't match the stack entry
361+
// — Navigation.goBack() then REPLACEs instead of POPs and crashes. Build the backTo URL
362+
// explicitly there. The create flow has no tab navigator, so the production getActiveRoute()
363+
// path is correct (GH #90037).
364+
const waypointBackTo = isEditing
365+
? ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(action, iouType, transactionID, report?.reportID ?? reportID, backTo)
366+
: Navigation.getActiveRoute();
365367
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(action, iouWaypointType, transactionID, report?.reportID ?? reportID, index.toString(), waypointBackTo));
366368
},
367-
[action, iouType, transactionID, report?.reportID, reportID, backTo, isEditingSplit],
369+
[action, iouType, transactionID, report?.reportID, reportID, backTo, isEditingSplit, isEditing],
368370
);
369371

370372
const navigateToNextStep = useCallback(() => {

tests/ui/IOURequestStepDistanceTest.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import OnyxListItemProvider from '@components/OnyxListItemProvider';
1111
import IOURequestStepDistance from '@pages/iou/request/step/IOURequestStepDistance';
1212
import CONST from '@src/CONST';
1313
import ONYXKEYS from '@src/ONYXKEYS';
14+
import ROUTES from '@src/ROUTES';
1415
import SCREENS from '@src/SCREENS';
1516
import type {Report, Transaction} from '@src/types/onyx';
1617
import type * as IOU from '../../src/libs/actions/IOU';
@@ -454,3 +455,93 @@ describe('IOURequestStepDistance - submitManualDistance', () => {
454455
expect(saveButtons.length).toBeGreaterThan(0);
455456
});
456457
});
458+
459+
describe('IOURequestStepDistance - navigateToWaypointEditPage backTo (GH #90037)', () => {
460+
const Navigation = jest.requireMock<{navigate: jest.Mock; getActiveRoute: jest.Mock}>('@libs/Navigation/Navigation');
461+
462+
beforeAll(() => {
463+
Onyx.init({
464+
keys: ONYXKEYS,
465+
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
466+
});
467+
});
468+
469+
beforeEach(async () => {
470+
jest.clearAllMocks();
471+
Navigation.getActiveRoute.mockReturnValue('');
472+
await Onyx.clear();
473+
await waitForBatchedUpdates();
474+
});
475+
476+
it('uses the explicit step-distance route as backTo in the edit flow (the tab navigator would otherwise add a tab suffix that breaks goBack)', async () => {
477+
await signInWithTestUser(ACCOUNT_ID, ACCOUNT_LOGIN);
478+
const report = createTestReport();
479+
480+
await act(async () => {
481+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
482+
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${TRANSACTION_ID}`, createDistanceTransaction());
483+
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID}`, null);
484+
await Onyx.merge(ONYXKEYS.IS_LOADING_APP, false);
485+
});
486+
487+
renderEditMode();
488+
await waitForBatchedUpdatesWithAct();
489+
490+
const startWaypoint = screen.getByAccessibilityHint(/123 Main St/);
491+
fireEvent.press(startWaypoint, {nativeEvent: {}, type: 'press', target: startWaypoint, currentTarget: startWaypoint});
492+
493+
expect(Navigation.navigate).toHaveBeenCalledWith(
494+
ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(
495+
CONST.IOU.ACTION.EDIT,
496+
CONST.IOU.TYPE.SUBMIT,
497+
TRANSACTION_ID,
498+
REPORT_ID,
499+
'0',
500+
ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, TRANSACTION_ID, REPORT_ID),
501+
),
502+
);
503+
});
504+
505+
it('uses the current active route as backTo in the create flow (no tab navigator, so the production getActiveRoute path is correct)', async () => {
506+
await signInWithTestUser(ACCOUNT_ID, ACCOUNT_LOGIN);
507+
const report = createTestReport();
508+
const activeRoute = ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, TRANSACTION_ID, REPORT_ID);
509+
Navigation.getActiveRoute.mockReturnValue(activeRoute);
510+
511+
await act(async () => {
512+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);
513+
await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID}`, createDistanceTransaction());
514+
await Onyx.merge(ONYXKEYS.IS_LOADING_APP, false);
515+
});
516+
517+
render(
518+
<OnyxListItemProvider>
519+
<CurrentUserPersonalDetailsProvider>
520+
<IOURequestStepDistance
521+
route={{
522+
key: 'Money_Request_Step_Distance-test',
523+
name: SCREENS.MONEY_REQUEST.STEP_DISTANCE,
524+
params: {
525+
action: CONST.IOU.ACTION.CREATE as never,
526+
iouType: CONST.IOU.TYPE.SUBMIT,
527+
reportID: REPORT_ID,
528+
transactionID: TRANSACTION_ID,
529+
backTo: undefined as never,
530+
},
531+
}}
532+
// @ts-expect-error minimal navigation for test
533+
navigation={undefined}
534+
/>
535+
</CurrentUserPersonalDetailsProvider>
536+
</OnyxListItemProvider>,
537+
);
538+
await waitForBatchedUpdatesWithAct();
539+
540+
const startWaypoint = screen.getByAccessibilityHint(/123 Main St/);
541+
fireEvent.press(startWaypoint, {nativeEvent: {}, type: 'press', target: startWaypoint, currentTarget: startWaypoint});
542+
543+
expect(Navigation.navigate).toHaveBeenCalledWith(
544+
ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, TRANSACTION_ID, REPORT_ID, '0', activeRoute),
545+
);
546+
});
547+
});

0 commit comments

Comments
 (0)