11import { findFocusedRoute } from '@react-navigation/native' ;
22import { renderHook } from '@testing-library/react-native' ;
3- import { useEffect } from 'react' ;
3+ import { useEffect , useMemo } from 'react' ;
44import { clearActiveTransactionIDs , setActiveTransactionIDs } from '@libs/actions/TransactionThreadNavigation' ;
55import { navigationRef } from '@libs/Navigation/Navigation' ;
66import SCREENS from '@src/SCREENS' ;
@@ -29,19 +29,21 @@ jest.mock('@react-navigation/native', () => ({
2929 * to allow isolated testing of the useEffect behavior.
3030 */
3131function useActiveTransactionIDsEffect ( visualOrderTransactionIDs : string [ ] ) {
32+ const visualOrderTransactionIDsKey = useMemo ( ( ) => visualOrderTransactionIDs . join ( ',' ) , [ visualOrderTransactionIDs ] ) ;
33+
3234 useEffect ( ( ) => {
3335 const focusedRoute = findFocusedRoute ( navigationRef . getRootState ( ) ) ;
3436 if ( focusedRoute ?. name !== SCREENS . RIGHT_MODAL . SEARCH_REPORT ) {
3537 return ;
3638 }
3739 setActiveTransactionIDs ( visualOrderTransactionIDs ) ;
38- } , [ visualOrderTransactionIDs ] ) ;
39-
40- useEffect ( ( ) => {
4140 return ( ) => {
4241 clearActiveTransactionIDs ( ) ;
4342 } ;
44- } , [ ] ) ;
43+ // eslint-disable-next-line react-hooks/exhaustive-deps -- visualOrderTransactionIDsKey is a primitive proxy for the array
44+ } , [ visualOrderTransactionIDsKey ] ) ;
45+
46+ return { visualOrderTransactionIDsKey} ;
4547}
4648
4749describe ( 'MoneyRequestReportTransactionList - Active Transaction IDs Effect' , ( ) => {
@@ -110,7 +112,7 @@ describe('MoneyRequestReportTransactionList - Active Transaction IDs Effect', ()
110112 expect ( mockClearActiveTransactionIDs ) . toHaveBeenCalledTimes ( 1 ) ;
111113 } ) ;
112114
113- it ( 'should call clearActiveTransactionIDs on unmount even when route was NOT SEARCH_REPORT' , ( ) => {
115+ it ( 'should NOT call clearActiveTransactionIDs on unmount when route was NOT SEARCH_REPORT' , ( ) => {
114116 // Given the focused route is NOT SEARCH_REPORT
115117 mockFindFocusedRoute . mockReturnValue ( { name : 'SomeOtherRoute' , key : 'test-key' } ) ;
116118
@@ -121,8 +123,8 @@ describe('MoneyRequestReportTransactionList - Active Transaction IDs Effect', ()
121123
122124 unmount ( ) ;
123125
124- // Then clearActiveTransactionIDs should still be called (cleanup runs on unmount regardless of route )
125- expect ( mockClearActiveTransactionIDs ) . toHaveBeenCalledTimes ( 1 ) ;
126+ // Then clearActiveTransactionIDs should NOT be called (since the effect returned early, no cleanup was registered )
127+ expect ( mockClearActiveTransactionIDs ) . not . toHaveBeenCalled ( ) ;
126128 } ) ;
127129
128130 it ( 'should update active transaction IDs when the list changes' , ( ) => {
@@ -148,7 +150,7 @@ describe('MoneyRequestReportTransactionList - Active Transaction IDs Effect', ()
148150 expect ( mockSetActiveTransactionIDs ) . toHaveBeenLastCalledWith ( newTransactionIDs ) ;
149151 } ) ;
150152
151- it ( 'should call setActiveTransactionIDs on reference change without clearing first (idempotent guard is in the action layer) ' , ( ) => {
153+ it ( 'should NOT re-fire when array reference changes but content is the same ' , ( ) => {
152154 // Given the focused route is SEARCH_REPORT
153155 mockFindFocusedRoute . mockReturnValue ( { name : SCREENS . RIGHT_MODAL . SEARCH_REPORT , key : 'test-key' } ) ;
154156
@@ -165,11 +167,9 @@ describe('MoneyRequestReportTransactionList - Active Transaction IDs Effect', ()
165167 const sameContentNewArray = [ 'trans1' , 'trans2' ] ;
166168 rerender ( { ids : sameContentNewArray } ) ;
167169
168- // Then the effect fires (new reference), but setActiveTransactionIDs internally skips the Onyx write.
169- // Crucially, clearActiveTransactionIDs is NOT called on re-render (only on unmount),
170- // preventing the null→same-IDs flash.
171- expect ( mockSetActiveTransactionIDs ) . toHaveBeenCalledTimes ( 2 ) ;
172- expect ( mockSetActiveTransactionIDs ) . toHaveBeenLastCalledWith ( sameContentNewArray ) ;
170+ // Then the effect should NOT re-fire because the join(',') key hasn't changed.
171+ // This prevents overwriting IDs set by other callers (e.g. TransactionDuplicateReview.onPreviewPressed).
172+ expect ( mockSetActiveTransactionIDs ) . toHaveBeenCalledTimes ( 1 ) ;
173173 expect ( mockClearActiveTransactionIDs ) . not . toHaveBeenCalled ( ) ;
174174 } ) ;
175175
0 commit comments