11import { renderHook } from '@testing-library/react-native' ;
22import getPathFromState from '@libs/Navigation/helpers/getPathFromState' ;
33import Navigation from '@libs/Navigation/Navigation' ;
4+ import navigationRef from '@libs/Navigation/navigationRef' ;
45import NAVIGATORS from '@src/NAVIGATORS' ;
6+ import ONYXKEYS from '@src/ONYXKEYS' ;
57import ROUTES from '@src/ROUTES' ;
68import SCREENS from '@src/SCREENS' ;
79import createRandomPolicy from '../../utils/collections/policies' ;
@@ -19,9 +21,6 @@ jest.mock('@hooks/useResponsiveLayout', () => () => mockResponsiveLayout());
1921
2022jest . mock ( '@hooks/useCurrentUserPersonalDetails' , ( ) => ( ) => ( { login : 'test@example.com' } ) ) ;
2123
22- const mockRootState = jest . fn ( ( ) : unknown => undefined ) ;
23- jest . mock ( '@hooks/useRootNavigationState' , ( ) => ( selector : ( state : unknown ) => unknown ) => selector ( mockRootState ( ) ) ) ;
24-
2524const mockUseOnyx = jest . fn ( ) . mockReturnValue ( [ undefined ] ) ;
2625jest . mock ( '@hooks/useOnyx' , ( ) => ( key : unknown , opts ?: unknown ) => mockUseOnyx ( key , opts ) as unknown [ ] ) ;
2726
@@ -35,6 +34,9 @@ jest.mock('@libs/Navigation/navigationRef', () => ({
3534
3635jest . mock ( '@react-navigation/native' , ( ) => ( {
3736 findFocusedRoute : jest . fn ( ( ) => ( { name : 'some-screen' } ) ) ,
37+ StackActions : {
38+ pop : jest . fn ( ( count : number ) => ( { type : 'POP' , payload : { count} } ) ) ,
39+ } ,
3840} ) ) ;
3941
4042jest . mock ( '@libs/Navigation/Navigation' , ( ) => ( {
@@ -55,6 +57,7 @@ jest.mock('@libs/PolicyUtils', () => ({
5557const fakePolicyID = 'ABCD1234' ;
5658const mockPolicy = { ...createRandomPolicy ( 0 ) , id : fakePolicyID } ;
5759const mockedGetPathFromState = getPathFromState as jest . MockedFunction < typeof getPathFromState > ;
60+ const mockedGetRootState = navigationRef . getRootState as jest . Mock ;
5861
5962const useRestoreWorkspacesTabOnNavigate = ( require ( '@hooks/useRestoreWorkspacesTabOnNavigate' ) as { default : ( ) => ( ) => void } ) . default ;
6063
@@ -63,9 +66,9 @@ const PolicyUtils = require('@libs/PolicyUtils') as {shouldShowPolicy: jest.Mock
6366const lastVisitedTabPathUtils = require ( '@libs/Navigation/helpers/lastVisitedTabPathUtils' ) as { getWorkspacesTabStateFromSessionStorage : jest . Mock } ;
6467
6568function setupOnyxForPolicy ( ) {
66- mockUseOnyx . mockImplementation ( ( _key : unknown , opts ?: { selector ?: ( data : unknown ) => unknown } ) => {
67- if ( opts ?. selector ) {
68- return [ opts . selector ( { [ `policy_ ${ fakePolicyID } ` ] : mockPolicy } ) ] ;
69+ mockUseOnyx . mockImplementation ( ( key : unknown ) => {
70+ if ( key === ONYXKEYS . COLLECTION . POLICY ) {
71+ return [ { [ `${ ONYXKEYS . COLLECTION . POLICY } ${ fakePolicyID } ` ] : mockPolicy } ] ;
6972 }
7073 return [ undefined ] ;
7174 } ) ;
@@ -100,13 +103,14 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
100103 PolicyUtils . shouldShowPolicy . mockReturnValue ( true ) ;
101104 PolicyUtils . isPendingDeletePolicy . mockReturnValue ( false ) ;
102105 mockedGetPathFromState . mockReset ( ) ;
106+ mockedGetRootState . mockReturnValue ( { routes : [ ] } ) ;
103107 } ) ;
104108
105109 it ( 'restores to the last visited workspace when re-entering the Workspaces tab' , ( ) => {
106110 setupOnyxForPolicy ( ) ;
107111 const restoredPath = `/workspaces/${ fakePolicyID } ` as const ;
108112 mockedGetPathFromState . mockReturnValue ( restoredPath ) ;
109- mockRootState . mockReturnValue (
113+ mockedGetRootState . mockReturnValue (
110114 buildStateWithUserOnDifferentTab ( [
111115 {
112116 name : NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR ,
@@ -122,7 +126,7 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
122126 } ) ;
123127
124128 it ( 'falls back to the workspaces list when no workspace was previously visited' , ( ) => {
125- mockRootState . mockReturnValue ( {
129+ mockedGetRootState . mockReturnValue ( {
126130 routes : [
127131 {
128132 name : NAVIGATORS . TAB_NAVIGATOR ,
@@ -141,7 +145,7 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
141145 PolicyUtils . isPendingDeletePolicy . mockReturnValue ( true ) ;
142146
143147 setupOnyxForPolicy ( ) ;
144- mockRootState . mockReturnValue (
148+ mockedGetRootState . mockReturnValue (
145149 buildStateWithUserOnDifferentTab ( [
146150 {
147151 name : NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR ,
@@ -162,7 +166,7 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
162166 setupOnyxForPolicy ( ) ;
163167 const restoredPath = `/workspaces/${ fakePolicyID } /workflows` as const ;
164168 mockedGetPathFromState . mockReturnValue ( restoredPath ) ;
165- mockRootState . mockReturnValue (
169+ mockedGetRootState . mockReturnValue (
166170 buildStateWithUserOnDifferentTab ( [
167171 {
168172 name : NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR ,
@@ -188,9 +192,7 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
188192 // TabNavigator instance still alive in the root stack to recover the user's last workspace sub-page.
189193 it ( 'reads workspace state from an older TabNavigator instance when the topmost one is empty' , ( ) => {
190194 setupOnyxForPolicy ( ) ;
191- const restoredPath = `/workspaces/${ fakePolicyID } /workflows` as const ;
192- mockedGetPathFromState . mockReturnValue ( restoredPath ) ;
193- mockRootState . mockReturnValue ( {
195+ mockedGetRootState . mockReturnValue ( {
194196 routes : [
195197 // Older TabNavigator: still holds the workspace state with WORKFLOWS focused.
196198 {
@@ -233,15 +235,18 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
233235 const { result} = renderHook ( ( ) => useRestoreWorkspacesTabOnNavigate ( ) ) ;
234236 result . current ( ) ;
235237
236- expect ( Navigation . navigate ) . toHaveBeenCalledWith ( restoredPath ) ;
238+ // The older TabNavigator is reached via StackActions.pop (popping the newer empty one off the root stack),
239+ // not via a fresh Navigation.navigate. Verify dispatch was called with a POP action.
240+ expect ( navigationRef . dispatch ) . toHaveBeenCalledWith ( expect . objectContaining ( { type : 'POP' } ) ) ;
241+ expect ( Navigation . navigate ) . not . toHaveBeenCalled ( ) ;
237242 } ) ;
238243
239244 // On narrow layouts (mobile), the URL-based restore is skipped: we always land on the workspace's
240245 // initial page so the user can navigate inward via the side-list — matches mobile UX and the docs.
241246 it ( 'falls back to the workspace initial page on narrow layouts even when a sub-page is focused' , ( ) => {
242247 mockResponsiveLayout . mockReturnValue ( { shouldUseNarrowLayout : true } ) ;
243248 setupOnyxForPolicy ( ) ;
244- mockRootState . mockReturnValue (
249+ mockedGetRootState . mockReturnValue (
245250 buildStateWithUserOnDifferentTab ( [
246251 {
247252 name : NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR ,
@@ -269,7 +274,7 @@ describe('useRestoreWorkspacesTabOnNavigate', () => {
269274 setupOnyxForPolicy ( ) ;
270275 const restoredPath = `/workspaces/${ fakePolicyID } /workflows` as const ;
271276 mockedGetPathFromState . mockReturnValue ( restoredPath ) ;
272- mockRootState . mockReturnValue ( {
277+ mockedGetRootState . mockReturnValue ( {
273278 routes : [
274279 {
275280 name : NAVIGATORS . TAB_NAVIGATOR ,
0 commit comments