diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
index a254ca8b0d83..a1286f39fe66 100644
--- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
+++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
@@ -551,6 +551,7 @@ function ComposerWithSuggestions({
setIsFullComposerAvailable={setIsFullComposerAvailable}
isComposerFullSize={isComposerFullSize}
value={value}
+ testID="composer"
numberOfLines={numberOfLines}
onNumberOfLinesChange={updateNumberOfLines}
shouldCalculateCaretPosition
diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js
index e26aae7be7c5..2bd969364e31 100644
--- a/src/pages/home/report/ReportActionsList.js
+++ b/src/pages/home/report/ReportActionsList.js
@@ -415,6 +415,7 @@ function ReportActionsList({
>
diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js
index f4dcd969923f..991ca82da1b6 100644
--- a/tests/perf-test/ReportActionsList.perf-test.js
+++ b/tests/perf-test/ReportActionsList.perf-test.js
@@ -13,6 +13,7 @@ import {ActionListContext, ReactionListContext} from '../../src/pages/home/Repor
import variables from '../../src/styles/variables';
import * as LHNTestUtils from '../utils/LHNTestUtils';
import PusherHelper from '../utils/PusherHelper';
+import * as ReportTestUtils from '../utils/ReportTestUtils';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
@@ -58,7 +59,7 @@ afterAll(() => {
const mockOnLayout = jest.fn();
const mockOnScroll = jest.fn();
-const mockLoadMoreChats = jest.fn();
+const mockLoadChats = jest.fn();
const mockRef = {current: null};
// Initialize the network key for OfflineWithFeedback
@@ -74,49 +75,6 @@ afterEach(() => {
PusherHelper.teardown();
});
-const getFakeReportAction = (index) => ({
- actionName: 'ADDCOMMENT',
- actorAccountID: index,
- automatic: false,
- avatar: '',
- created: '2023-09-12 16:27:35.124',
- isAttachment: true,
- isFirstItem: false,
- lastModified: '2021-07-14T15:00:00Z',
- message: [
- {
- html: 'hey',
- isDelatedParentAction: false,
- isEdited: false,
- reactions: [],
- text: 'test',
- type: 'TEXT',
- whisperedTo: [],
- },
- ],
- originalMessage: {
- html: 'hey',
- lastModified: '2021-07-14T15:00:00Z',
- },
- pendingAction: null,
- person: [
- {
- type: 'TEXT',
- style: 'strong',
- text: 'email@test.com',
- },
- ],
- previousReportActionID: '1',
- reportActionID: index.toString(),
- reportActionTimestamp: 1696243169753,
- sequenceNumber: 2,
- shouldShow: true,
- timestamp: 1696243169,
- whisperedToAccountIDs: [],
-});
-
-const getMockedSortedReportActions = (length = 100) => Array.from({length}, (__, i) => getFakeReportAction(i));
-
const currentUserAccountID = 5;
function ReportActionsListWrapper() {
@@ -125,11 +83,13 @@ function ReportActionsListWrapper() {
diff --git a/tests/perf-test/ReportScreen.perf-test.js b/tests/perf-test/ReportScreen.perf-test.js
new file mode 100644
index 000000000000..578546cb4679
--- /dev/null
+++ b/tests/perf-test/ReportScreen.perf-test.js
@@ -0,0 +1,225 @@
+import {fireEvent, screen} from '@testing-library/react-native';
+import React from 'react';
+import Onyx from 'react-native-onyx';
+import {measurePerformance} from 'reassure';
+import ComposeProviders from '../../src/components/ComposeProviders';
+import DragAndDropProvider from '../../src/components/DragAndDrop/Provider';
+import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
+import OnyxProvider from '../../src/components/OnyxProvider';
+import {CurrentReportIDContextProvider} from '../../src/components/withCurrentReportID';
+import {KeyboardStateProvider} from '../../src/components/withKeyboardState';
+import {WindowDimensionsProvider} from '../../src/components/withWindowDimensions';
+import CONST from '../../src/CONST';
+import * as Localize from '../../src/libs/Localize';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import {ReportAttachmentsProvider} from '../../src/pages/home/report/ReportAttachmentsContext';
+import ReportScreen from '../../src/pages/home/ReportScreen';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import PusherHelper from '../utils/PusherHelper';
+import * as ReportTestUtils from '../utils/ReportTestUtils';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
+
+jest.setTimeout(60000);
+
+jest.mock('react-native-reanimated', () => ({
+ ...jest.requireActual('react-native-reanimated/mock'),
+ useSharedValue: jest.fn,
+ useAnimatedStyle: jest.fn,
+ useAnimatedRef: jest.fn,
+}));
+
+jest.mock('../../src/components/withNavigationFocus', () => (Component) => {
+ function WithNavigationFocus(props) {
+ return (
+
+ );
+ }
+
+ WithNavigationFocus.displayName = 'WithNavigationFocus';
+
+ return WithNavigationFocus;
+});
+
+jest.mock('../../src/hooks/useEnvironment', () =>
+ jest.fn(() => ({
+ environment: 'development',
+ environmentURL: 'https://new.expensify.com',
+ isProduction: false,
+ isDevelopment: true,
+ })),
+);
+
+jest.mock('../../src/libs/Permissions', () => ({
+ canUseTasks: jest.fn(() => true),
+ canUseLinkPreviews: jest.fn(() => true),
+}));
+
+jest.mock('../../src/libs/Navigation/Navigation');
+
+const mockedNavigate = jest.fn();
+jest.mock('@react-navigation/native', () => {
+ const actualNav = jest.requireActual('@react-navigation/native');
+ return {
+ ...actualNav,
+ useFocusEffect: jest.fn(),
+ useIsFocused: () => ({
+ navigate: mockedNavigate,
+ }),
+ useRoute: () => jest.fn(),
+ useNavigation: () => ({
+ navigate: jest.fn(),
+ addListener: () => jest.fn(),
+ }),
+ createNavigationContainerRef: jest.fn(),
+ };
+});
+
+// mock PortalStateContext
+jest.mock('@gorhom/portal');
+
+beforeAll(() =>
+ Onyx.init({
+ keys: ONYXKEYS,
+ safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
+ registerStorageEventListener: () => {},
+ }),
+);
+
+// Initialize the network key for OfflineWithFeedback
+beforeEach(() => {
+ global.fetch = TestHelper.getGlobalFetchMock();
+ wrapOnyxWithWaitForBatchedUpdates(Onyx);
+ Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false});
+});
+
+// Clear out Onyx after each test so that each test starts with a clean state
+afterEach(() => {
+ Onyx.clear();
+ PusherHelper.teardown();
+});
+
+function ReportScreenWrapper(args) {
+ return (
+
+
+
+ );
+}
+
+test('should render ReportScreen with composer interactions', () => {
+ const scenario = async () => {
+ // Query for the report list
+ await screen.findByTestId('report-actions-list');
+
+ // Query for the composer
+ const composer = await screen.findByTestId('composer');
+ expect(composer).toBeDefined();
+
+ // Type in the composer
+ fireEvent.changeText(composer, 'Test message');
+
+ const hintSendButtonText = Localize.translateLocal('common.send');
+
+ // Query for the send button
+ const sendButton = await screen.findByLabelText(hintSendButtonText);
+ expect(sendButton).toBeDefined();
+
+ // Click on the send button
+ fireEvent.press(sendButton);
+
+ const hintHeaderText = Localize.translateLocal('common.back');
+
+ // Query for the header
+ const header = await screen.findByLabelText(hintHeaderText);
+ expect(header).toBeDefined();
+ };
+
+ const policy = {
+ policyID: 1,
+ name: 'Testing Policy',
+ };
+
+ const report = LHNTestUtils.getFakeReport();
+ const reportActions = ReportTestUtils.getMockedReportsMap(1000);
+ const mockRoute = {params: {reportID: '1'}};
+
+ return waitForBatchedUpdates()
+ .then(() =>
+ Onyx.multiSet({
+ [ONYXKEYS.IS_SIDEBAR_LOADED]: true,
+ [`${ONYXKEYS.COLLECTION.REPORT}${mockRoute.params.reportID}`]: report,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${mockRoute.params.reportID}`]: reportActions,
+ [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails,
+ [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS],
+ [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy,
+ [`${ONYXKEYS.COLLECTION.REPORT_METADATA}${mockRoute.params.reportID}`]: {
+ isLoadingReportActions: false,
+ },
+ }),
+ )
+ .then(() => measurePerformance(, {scenario}));
+});
+
+test('should press of the report item', () => {
+ const scenario = async () => {
+ // Query for the report list
+ await screen.findByTestId('report-actions-list');
+
+ // Query for the composer
+ await screen.findByTestId('composer');
+
+ const hintReportPreviewText = Localize.translateLocal('iou.viewDetails');
+
+ // Query for report preview buttons
+ const reportPreviewButtons = await screen.findAllByLabelText(hintReportPreviewText);
+
+ expect(reportPreviewButtons.length).toBeDefined();
+
+ // click on the report preview button
+ fireEvent.press(reportPreviewButtons[0]);
+ };
+
+ const policy = {
+ policyID: 123,
+ name: 'Testing Policy',
+ };
+
+ const report = LHNTestUtils.getFakeReport();
+ const reportActions = ReportTestUtils.getMockedReportsMap(1000);
+ const mockRoute = {params: {reportID: '2'}};
+
+ return waitForBatchedUpdates()
+ .then(() =>
+ Onyx.multiSet({
+ [ONYXKEYS.IS_SIDEBAR_LOADED]: true,
+ [`${ONYXKEYS.COLLECTION.REPORT}${mockRoute.params.reportID}`]: report,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${mockRoute.params.reportID}`]: reportActions,
+ [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails,
+ [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS],
+ [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy,
+ [`${ONYXKEYS.COLLECTION.REPORT_METADATA}${mockRoute.params.reportID}`]: {
+ isLoadingReportActions: false,
+ },
+ }),
+ )
+ .then(() => measurePerformance(, {scenario}));
+});
diff --git a/tests/utils/ReportTestUtils.js b/tests/utils/ReportTestUtils.js
new file mode 100644
index 000000000000..48e5ebfaa56d
--- /dev/null
+++ b/tests/utils/ReportTestUtils.js
@@ -0,0 +1,61 @@
+import _ from 'underscore';
+
+const actionNames = ['ADDCOMMENT', 'IOU', 'REPORTPREVIEW'];
+
+const getFakeReportAction = (index, actionName) => ({
+ actionName,
+ actorAccountID: index,
+ automatic: false,
+ avatar: '',
+ created: '2023-09-12 16:27:35.124',
+ isAttachment: true,
+ isFirstItem: false,
+ lastModified: '2021-07-14T15:00:00Z',
+ message: [
+ {
+ html: 'hey',
+ isDelatedParentAction: false,
+ isEdited: false,
+ reactions: [],
+ text: 'test',
+ type: 'TEXT',
+ whisperedTo: [],
+ },
+ ],
+ originalMessage: {
+ html: 'hey',
+ lastModified: '2021-07-14T15:00:00Z',
+ // IOUReportID: index,
+ linkedReportID: index.toString(),
+ },
+ pendingAction: null,
+ person: [
+ {
+ type: 'TEXT',
+ style: 'strong',
+ text: 'email@test.com',
+ },
+ ],
+ previousReportActionID: '1',
+ reportActionID: index.toString(),
+ reportActionTimestamp: 1696243169753,
+ sequenceNumber: 0,
+ shouldShow: true,
+ timestamp: 1696243169,
+ whisperedToAccountIDs: [],
+});
+
+const getMockedSortedReportActions = (length = 100) => Array.from({length}, (__, i) => getFakeReportAction(i));
+
+const getMockedReportsMap = (length = 100) => {
+ const mockReports = Array.from({length}, (__, i) => {
+ const reportID = i + 1;
+ const actionName = i === 0 ? 'CREATED' : actionNames[i % actionNames.length];
+ const reportAction = getFakeReportAction(reportID, actionName);
+
+ return {[reportID]: reportAction};
+ });
+ return _.assign({}, ...mockReports);
+};
+
+export {getFakeReportAction, getMockedSortedReportActions, getMockedReportsMap};