11import { act , renderHook } from '@testing-library/react-native' ;
22import { DeviceEventEmitter } from 'react-native' ;
33import useUnreadMarker from '@hooks/useUnreadMarker' ;
4+ import ONYXKEYS from '@src/ONYXKEYS' ;
45import type * as OnyxTypes from '@src/types/onyx' ;
56import { getFakeReportAction } from '../utils/ReportTestUtils' ;
67
@@ -11,6 +12,7 @@ const LAST_READ_TIME = '2023-01-01 10:00:00.000';
1112
1213let mockIsAnonymousUser = false ;
1314let mockLastReadTime : string = LAST_READ_TIME ;
15+ let mockLastReadTimeByReportID : Record < string , string > = { } ;
1416
1517jest . mock ( '@hooks/useCurrentUserPersonalDetails' , ( ) => ( {
1618 __esModule : true ,
@@ -22,9 +24,13 @@ jest.mock('@hooks/useIsAnonymousUser', () => ({
2224 default : ( ) => mockIsAnonymousUser ,
2325} ) ) ;
2426
27+ // The hook subscribes to `${ONYXKEYS.COLLECTION.REPORT}${reportID}` with a selector that returns
28+ // `lastReadTime`. The implementation is set in beforeEach so it can use ONYXKEYS freely (a jest.mock
29+ // factory cannot reference out-of-scope variables).
30+ const mockUseOnyx = jest . fn < [ string ] , [ string ] > ( ) ;
2531jest . mock ( '@hooks/useOnyx' , ( ) => ( {
2632 __esModule : true ,
27- default : ( ) => [ mockLastReadTime ] ,
33+ default : ( key : string ) => mockUseOnyx ( key ) ,
2834} ) ) ;
2935
3036function makeAction ( reportActionID : string , overrides : Partial < OnyxTypes . ReportAction > = { } ) : OnyxTypes . ReportAction {
@@ -55,6 +61,11 @@ describe('useUnreadMarker', () => {
5561 beforeEach ( ( ) => {
5662 mockIsAnonymousUser = false ;
5763 mockLastReadTime = LAST_READ_TIME ;
64+ mockLastReadTimeByReportID = { } ;
65+ mockUseOnyx . mockImplementation ( ( key ) => {
66+ const reportID = key . replace ( ONYXKEYS . COLLECTION . REPORT , '' ) ;
67+ return [ mockLastReadTimeByReportID [ reportID ] ?? mockLastReadTime ] ;
68+ } ) ;
5869 } ) ;
5970
6071 it ( 'returns [null, -1] for an anonymous user' , ( ) => {
@@ -107,4 +118,24 @@ describe('useUnreadMarker', () => {
107118 expect ( result . current . unreadMarkerReportActionID ) . toBeNull ( ) ;
108119 expect ( result . current . unreadMarkerReportActionIndex ) . toBe ( - 1 ) ;
109120 } ) ;
121+
122+ it ( 'seeds the marker from the switched-to report lastReadTime (one mount per report)' , ( ) => {
123+ // Setup: report 'A' was last read at 10:00 and 'B' at 12:00; one action from another user lands
124+ // at 11:00 — after A's read time (unread on A) but before B's read time (already read on B).
125+ mockLastReadTimeByReportID = {
126+ A : '2023-01-01 10:00:00.000' ,
127+ B : '2023-01-01 12:00:00.000' ,
128+ } ;
129+ const action = makeAction ( 'msg' , { created : '2023-01-01 11:00:00.000' } ) ;
130+
131+ // Mounted on A: 11:00 is after A's 10:00 read time → unread → marker lands on the action.
132+ const { result : resultA } = renderUnreadMarker ( { reportID : 'A' , sortedVisibleReportActions : [ action ] , sortedReportActions : [ action ] } ) ;
133+ expect ( resultA . current . unreadMarkerReportActionID ) . toBe ( 'msg' ) ;
134+ expect ( resultA . current . unreadMarkerReportActionIndex ) . toBe ( 0 ) ;
135+
136+ // Mounted on B: 11:00 is before B's 12:00 read time → already read → no marker.
137+ const { result : resultB } = renderUnreadMarker ( { reportID : 'B' , sortedVisibleReportActions : [ action ] , sortedReportActions : [ action ] } ) ;
138+ expect ( resultB . current . unreadMarkerReportActionID ) . toBeNull ( ) ;
139+ expect ( resultB . current . unreadMarkerReportActionIndex ) . toBe ( - 1 ) ;
140+ } ) ;
110141} ) ;
0 commit comments