Skip to content

Commit 7e97843

Browse files
committed
fix: add missing MentionReportContext and unit tests
1 parent 8227110 commit 7e97843

3 files changed

Lines changed: 164 additions & 25 deletions

File tree

src/pages/inbox/report/actionContents/ConfirmWhisperContent.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import {View} from 'react-native';
33
import type {OnyxEntry} from 'react-native-onyx';
4+
import MentionReportContext from '@components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext';
45
import type {ActionableItem} from '@components/ReportActionItem/ActionableItemButtons';
56
import ActionableItemButtons from '@components/ReportActionItem/ActionableItemButtons';
67
import useReportIsArchived from '@hooks/useReportIsArchived';
@@ -20,6 +21,7 @@ type ConfirmWhisperContentProps = {
2021
function ConfirmWhisperContent({action, reportID, originalReportID, report, originalReport}: ConfirmWhisperContentProps) {
2122
const reportActionReport = originalReport ?? report;
2223
const isOriginalReportArchived = useReportIsArchived(originalReportID);
24+
const mentionReportContextValue = {currentReportID: report?.reportID, exactlyMatch: true};
2325

2426
const buttons: ActionableItem[] = [
2527
{
@@ -32,18 +34,20 @@ function ConfirmWhisperContent({action, reportID, originalReportID, report, orig
3234
];
3335

3436
return (
35-
<View>
36-
<ReportActionItemMessage
37-
action={action}
38-
reportID={reportID}
39-
displayAsGroup
40-
/>
41-
<ActionableItemButtons
42-
items={buttons}
43-
shouldUseLocalization
44-
layout="horizontal"
45-
/>
46-
</View>
37+
<MentionReportContext.Provider value={mentionReportContextValue}>
38+
<View>
39+
<ReportActionItemMessage
40+
action={action}
41+
reportID={reportID}
42+
displayAsGroup
43+
/>
44+
<ActionableItemButtons
45+
items={buttons}
46+
shouldUseLocalization
47+
layout="horizontal"
48+
/>
49+
</View>
50+
</MentionReportContext.Provider>
4751
);
4852
}
4953

src/pages/inbox/report/actionContents/ReportMentionWhisperContent.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import {View} from 'react-native';
33
import type {OnyxEntry} from 'react-native-onyx';
44
import type {ValueOf} from 'type-fest';
5+
import MentionReportContext from '@components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext';
56
import type {ActionableItem} from '@components/ReportActionItem/ActionableItemButtons';
67
import ActionableItemButtons from '@components/ReportActionItem/ActionableItemButtons';
78
import {getOriginalMessage} from '@libs/ReportActionsUtils';
@@ -26,6 +27,7 @@ type ReportMentionWhisperContentProps = {
2627
function ReportMentionWhisperContent({action, reportID, report, originalReport, isReportArchived, resolveActionableReportMentionWhisper}: ReportMentionWhisperContentProps) {
2728
const reportActionReport = originalReport ?? report;
2829
const resolution = getOriginalMessage(action)?.resolution;
30+
const mentionReportContextValue = {currentReportID: report?.reportID, exactlyMatch: true};
2931

3032
const buttons: ActionableItem[] = resolution
3133
? []
@@ -44,20 +46,22 @@ function ReportMentionWhisperContent({action, reportID, report, originalReport,
4446
];
4547

4648
return (
47-
<View>
48-
<ReportActionItemMessage
49-
action={action}
50-
reportID={reportID}
51-
displayAsGroup
52-
/>
53-
{buttons.length > 0 && (
54-
<ActionableItemButtons
55-
items={buttons}
56-
shouldUseLocalization
57-
layout="horizontal"
49+
<MentionReportContext.Provider value={mentionReportContextValue}>
50+
<View>
51+
<ReportActionItemMessage
52+
action={action}
53+
reportID={reportID}
54+
displayAsGroup
5855
/>
59-
)}
60-
</View>
56+
{buttons.length > 0 && (
57+
<ActionableItemButtons
58+
items={buttons}
59+
shouldUseLocalization
60+
layout="horizontal"
61+
/>
62+
)}
63+
</View>
64+
</MentionReportContext.Provider>
6165
);
6266
}
6367

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
import {act, render, screen} from '@testing-library/react-native';
3+
import React from 'react';
4+
import Onyx from 'react-native-onyx';
5+
import OnyxListItemProvider from '@components/OnyxListItemProvider';
6+
import ConfirmWhisperContent from '@pages/inbox/report/actionContents/ConfirmWhisperContent';
7+
import ReportMentionWhisperContent from '@pages/inbox/report/actionContents/ReportMentionWhisperContent';
8+
import CONST from '@src/CONST';
9+
import ONYXKEYS from '@src/ONYXKEYS';
10+
import type {Report, ReportAction} from '@src/types/onyx';
11+
import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct';
12+
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
13+
14+
jest.mock('@libs/Navigation/helpers/isSearchTopmostFullScreenRoute', () => jest.fn(() => false));
15+
jest.mock('@navigation/Navigation', () => ({getActiveRoute: jest.fn(() => '')}));
16+
jest.mock('@hooks/useReportIsArchived', () => ({
17+
__esModule: true,
18+
default: jest.fn(() => false),
19+
}));
20+
21+
const REPORT_ID = 'report-100';
22+
const ROOM_ID = 'room-200';
23+
const POLICY_ID = 'workspace-abc';
24+
25+
// Mock ReportActionItemMessage to render a real MentionReportRenderer with a test tnode.
26+
// The whisper component provides MentionReportContext, the real renderer consumes it.
27+
jest.mock('@pages/inbox/report/ReportActionItemMessage', () => {
28+
const {default: Renderer} = jest.requireActual<{default: React.ComponentType<{tnode: unknown; TDefaultRenderer: () => null; style: Record<string, unknown>}>}>(
29+
'@components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer',
30+
);
31+
32+
// cspell:disable-next-line
33+
const tnode = {attributes: {reportid: ROOM_ID}, data: '#test-room'};
34+
return () => (
35+
<Renderer
36+
tnode={tnode}
37+
TDefaultRenderer={() => null}
38+
style={{}}
39+
/>
40+
);
41+
});
42+
43+
function createWhisperAction<T extends string>(actionName: T) {
44+
return {
45+
reportActionID: 'action-1',
46+
actorAccountID: 1,
47+
created: '2025-07-12 09:03:17.653',
48+
actionName,
49+
automatic: true,
50+
shouldShow: true,
51+
avatar: '',
52+
person: [{type: 'TEXT', style: 'strong', text: 'Test'}],
53+
message: [{type: 'COMMENT', html: 'whisper message', text: 'whisper message'}],
54+
originalMessage: {},
55+
} as ReportAction;
56+
}
57+
58+
const report = {
59+
reportID: REPORT_ID,
60+
policyID: POLICY_ID,
61+
} as Report;
62+
63+
describe('Whisper content components provide MentionReportContext so room mentions render as links', () => {
64+
beforeAll(() => {
65+
Onyx.init({keys: ONYXKEYS});
66+
});
67+
68+
beforeEach(async () => {
69+
wrapOnyxWithWaitForBatchedUpdates(Onyx);
70+
await act(async () => {
71+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {
72+
reportID: REPORT_ID,
73+
policyID: POLICY_ID,
74+
} as Report);
75+
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${ROOM_ID}`, {
76+
reportID: ROOM_ID,
77+
reportName: 'test-room',
78+
chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM,
79+
policyID: POLICY_ID,
80+
} as Report);
81+
});
82+
await waitForBatchedUpdatesWithAct();
83+
});
84+
85+
afterEach(async () => {
86+
await act(async () => {
87+
await Onyx.clear();
88+
});
89+
});
90+
91+
it('ReportMentionWhisperContent renders room mention as a link', async () => {
92+
const action = createWhisperAction(CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER);
93+
94+
render(
95+
<OnyxListItemProvider>
96+
<ReportMentionWhisperContent
97+
action={action as ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER>}
98+
reportID={REPORT_ID}
99+
report={report}
100+
originalReport={undefined}
101+
isReportArchived={false}
102+
resolveActionableReportMentionWhisper={jest.fn()}
103+
/>
104+
</OnyxListItemProvider>,
105+
);
106+
await waitForBatchedUpdatesWithAct();
107+
108+
expect(screen.getByText('#test-room')).toBeOnTheScreen();
109+
expect(screen.getByRole('link')).toBeOnTheScreen();
110+
});
111+
112+
it('ConfirmWhisperContent renders room mention as a link', async () => {
113+
const action = createWhisperAction(CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_INVITE_TO_SUBMIT_EXPENSE_CONFIRM_WHISPER);
114+
115+
render(
116+
<OnyxListItemProvider>
117+
<ConfirmWhisperContent
118+
action={action as ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_INVITE_TO_SUBMIT_EXPENSE_CONFIRM_WHISPER>}
119+
reportID={REPORT_ID}
120+
originalReportID={undefined}
121+
report={report}
122+
originalReport={undefined}
123+
/>
124+
</OnyxListItemProvider>,
125+
);
126+
await waitForBatchedUpdatesWithAct();
127+
128+
expect(screen.getByText('#test-room')).toBeOnTheScreen();
129+
expect(screen.getByRole('link')).toBeOnTheScreen();
130+
});
131+
});

0 commit comments

Comments
 (0)