Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/libs/Navigation/guards/OnboardingGuard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ function isCurrentlyOnTwoFactorSetupRoute(state: NavigationState): boolean {
}

function shouldPreventReset(state: NavigationState, action: NavigationAction) {
if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) {
// Browser back that pops the last history entry dispatches GO_BACK instead of RESET, and it reaches the root only when it would leave onboarding
const isGoBack = action.type === CONST.NAVIGATION.ACTION_TYPE.GO_BACK;
if (!isGoBack && (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload)) {
Comment on lines +154 to +155

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Don't pass payload-less back actions to findFocusedRoute

When browser back produces the payload-less action used by the new test ({type: 'GO_BACK'}), this condition now falls through to findFocusedRoute(action?.payload as NavigationState) below. The cast does not create a runtime state, and React Navigation's helper dereferences state.routes, so the guard throws before returning BLOCK or restoring browser history; the added test would fail for the same reason. Handle GO_BACK without attempting to derive a target route from its missing payload.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findFocusedRoute handles an undefined state. It uses optional chaining throughout (current?.routes[...]), so it returns undefined and the guard returns BLOCK. Verified with CommonActions.goBack() ({type: 'GO_BACK'}) on a nested onboarding state, and the new test fails without the fix (ALLOW).

return false;
}

Expand Down
18 changes: 18 additions & 0 deletions tests/unit/Navigation/guards/OnboardingGuard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,24 @@ describe('OnboardingGuard', () => {
expect(result.reason).toBe('Cannot reset to non-onboarding screen while on onboarding');
}
});

it('should BLOCK GO_BACK action when user is on onboarding', () => {
// Given a user who is currently on the onboarding purpose screen and has not yet completed onboarding
const onboardingState: NavigationState = {
key: 'root',
index: 0,
routeNames: [SCREENS.ONBOARDING.PURPOSE],
routes: [{key: 'purpose', name: SCREENS.ONBOARDING.PURPOSE}],
stale: false,
type: 'root',
};

// When the browser back button pops the last history entry, which React Navigation dispatches as GO_BACK
const result = OnboardingGuard.evaluate(onboardingState, {type: CONST.NAVIGATION.ACTION_TYPE.GO_BACK}, authenticatedContext);

// Then the action should be blocked because going back from onboarding would close the modal without finishing it
expect(result.type).toBe('BLOCK');
});
});

describe('skip onboarding conditions', () => {
Expand Down
Loading