From 09089048a261f382e90073af8e61090f4d55c02a Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Tue, 17 Oct 2023 16:40:10 +0200 Subject: [PATCH 1/3] feat: add perf tests to ReportActionsList --- src/pages/home/report/ReportActionItem.js | 1 + src/pages/home/report/ReportActionsList.js | 1 + .../perf-test/ReportActionsList.perf-test.js | 191 ++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 tests/perf-test/ReportActionsList.perf-test.js diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index f5ca7080249c..2d0ed2f76e86 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -606,6 +606,7 @@ function ReportActionItem(props) { preventDefaultContextMenu={!props.draftMessage && !hasErrors} withoutFocusOnSecondaryInteraction accessibilityLabel={props.translate('accessibilityHints.chatMessage')} + testID={props.action.reportActionID} > diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js new file mode 100644 index 000000000000..3b8d7afbfe25 --- /dev/null +++ b/tests/perf-test/ReportActionsList.perf-test.js @@ -0,0 +1,191 @@ +import {measurePerformance} from 'reassure'; +import Onyx from 'react-native-onyx'; +import {screen, fireEvent} from '@testing-library/react-native'; +import ReportActionsList from '../../src/pages/home/report/ReportActionsList'; +import ComposeProviders from '../../src/components/ComposeProviders'; +import OnyxProvider from '../../src/components/OnyxProvider'; +import {ReportAttachmentsProvider} from '../../src/pages/home/report/ReportAttachmentsContext'; +import {WindowDimensionsProvider} from '../../src/components/withWindowDimensions'; +import {LocaleContextProvider} from '../../src/components/LocaleContextProvider'; +import * as LHNTestUtils from '../utils/LHNTestUtils'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; +import PusherHelper from '../utils/PusherHelper'; +import variables from '../../src/styles/variables'; +import {ActionListContext, ReactionListContext} from '../../src/pages/home/ReportScreenContext'; + +const ONYXKEYS = { + PERSONAL_DETAILS_LIST: 'personalDetailsList', + SESSION: 'session', + COLLECTION: { + REPORT: 'report_', + REPORT_ACTIONS: 'reportActions_', + }, + NETWORK: 'network', +}; + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useRoute: () => jest.fn(), + }; +}); + +jest.mock('../../src/hooks/useLocalize', () => + jest.fn(() => ({ + translate: jest.fn(), + })), +); + +beforeAll(() => + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + registerStorageEventListener: () => {}, + }), +); + +afterAll(() => { + jest.clearAllMocks(); +}); + +const mockOnLayout = jest.fn(); +const mockOnScroll = jest.fn(); +const mockLoadMoreChats = jest.fn(); +const mockRef = {current: null}; + +// Initialize the network key for OfflineWithFeedback +beforeEach(() => { + PusherHelper.setup(); + wrapOnyxWithWaitForBatchedUpdates(Onyx); + return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); +}); + +// Clear out Onyx after each test so that each test starts with a clean slate +afterEach(() => { + jest.useRealTimers(); + Onyx.clear(); + 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) => { + const reportAction = getFakeReportAction(i); + return reportAction; + }); + +const currentUserAccountID = 5; + +function ReportActionsListWrapper() { + return ( + + + + + + + + ); +} + +test('should render ReportActionsList with 500 reportActions stored', () => { + const scenario = async () => { + await screen.findByTestId('report-actions-list'); + }; + + return waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, + }), + ) + .then(() => measurePerformance(, {scenario})); +}); + +test('should scroll and click some of the reports', () => { + const eventData = { + nativeEvent: { + contentOffset: { + y: variables.optionRowHeight * 5, + }, + contentSize: { + // Dimensions of the scrollable content + height: variables.optionRowHeight * 10, + width: 100, + }, + layoutMeasurement: { + // Dimensions of the device + height: variables.optionRowHeight * 5, + width: 100, + }, + }, + }; + + const scenario = async () => { + const reportActionsList = await screen.findByTestId('report-actions-list'); + expect(reportActionsList).toBeDefined(); + + fireEvent.scroll(reportActionsList, eventData); + + const reportItem = await screen.findByTestId('1'); + + fireEvent.press(reportItem, 'onLongPress'); + }; + + return waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, + }), + ) + .then(() => measurePerformance(, {scenario})); +}); From b9cb0d65d2c87b220e590499e6c655f0805f3a0d Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Wed, 18 Oct 2023 10:29:18 +0200 Subject: [PATCH 2/3] fixes after review --- src/pages/home/report/ReportActionItem.js | 1 - .../perf-test/ReportActionsList.perf-test.js | 45 +++++++++---------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 2d0ed2f76e86..f5ca7080249c 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -606,7 +606,6 @@ function ReportActionItem(props) { preventDefaultContextMenu={!props.draftMessage && !hasErrors} withoutFocusOnSecondaryInteraction accessibilityLabel={props.translate('accessibilityHints.chatMessage')} - testID={props.action.reportActionID} > (Component) => (props) => ( + +)); jest.mock('@react-navigation/native', () => { const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, - useRoute: () => jest.fn(), + useRoute: () => mockedNavigate, }; }); -jest.mock('../../src/hooks/useLocalize', () => - jest.fn(() => ({ - translate: jest.fn(), - })), -); - beforeAll(() => Onyx.init({ keys: ONYXKEYS, @@ -64,7 +62,6 @@ beforeEach(() => { // Clear out Onyx after each test so that each test starts with a clean slate afterEach(() => { - jest.useRealTimers(); Onyx.clear(); PusherHelper.teardown(); }); @@ -110,11 +107,7 @@ const getFakeReportAction = (index) => ({ whisperedToAccountIDs: [], }); -const getMockedSortedReportActions = (length = 100) => - Array.from({length}, (__, i) => { - const reportAction = getFakeReportAction(i); - return reportAction; - }); +const getMockedSortedReportActions = (length = 100) => Array.from({length}, (__, i) => getFakeReportAction(i)); const currentUserAccountID = 5; @@ -140,6 +133,9 @@ function ReportActionsListWrapper() { test('should render ReportActionsList with 500 reportActions stored', () => { const scenario = async () => { await screen.findByTestId('report-actions-list'); + const hintText = Localize.translateLocal('accessibilityHints.chatMessage'); + // Esure that the list of items are rendered + await screen.findAllByLabelText(hintText); }; return waitForBatchedUpdates() @@ -176,9 +172,10 @@ test('should scroll and click some of the reports', () => { fireEvent.scroll(reportActionsList, eventData); - const reportItem = await screen.findByTestId('1'); + const hintText = Localize.translateLocal('accessibilityHints.chatMessage'); + const reportItems = await screen.findAllByLabelText(hintText); - fireEvent.press(reportItem, 'onLongPress'); + fireEvent.press(reportItems[0], 'onLongPress'); }; return waitForBatchedUpdates() From d0877aea0fe758ed850360c1557194a4e22a9baf Mon Sep 17 00:00:00 2001 From: OlimpiaZurek Date: Fri, 20 Oct 2023 10:01:36 +0200 Subject: [PATCH 3/3] fix typo --- tests/perf-test/ReportActionsList.perf-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js index 180c15458f35..4d83cc435636 100644 --- a/tests/perf-test/ReportActionsList.perf-test.js +++ b/tests/perf-test/ReportActionsList.perf-test.js @@ -134,7 +134,7 @@ test('should render ReportActionsList with 500 reportActions stored', () => { const scenario = async () => { await screen.findByTestId('report-actions-list'); const hintText = Localize.translateLocal('accessibilityHints.chatMessage'); - // Esure that the list of items are rendered + // Ensure that the list of items is rendered await screen.findAllByLabelText(hintText); };