diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 4f9c2bd85633..0c30a182d589 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -92,6 +92,8 @@ import { isTaskAction, isThreadParentMessage, isUnapprovedAction, + isWhisperAction, + shouldReportActionBeVisible, withDEWRoutedActionsArray, } from '@libs/ReportActionsUtils'; import {computeReportName} from '@libs/ReportNameUtils'; @@ -197,13 +199,13 @@ import type { */ let allPersonalDetails: OnyxEntry; -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (value) => (allPersonalDetails = isEmptyObject(value) ? {} : value), }); const policies: OnyxCollection = {}; -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.COLLECTION.POLICY, callback: (policy, key) => { if (!policy || !key || !policy.name) { @@ -215,14 +217,14 @@ Onyx.connect({ }); let allPolicies: OnyxCollection = {}; -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.COLLECTION.POLICY, waitForCollectionCallback: true, callback: (val) => (allPolicies = val), }); let allReports: OnyxCollection; -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (value) => { @@ -231,7 +233,77 @@ Onyx.connect({ }); let allReportNameValuePairsOnyxConnect: OnyxCollection; -Onyx.connect({ + +const lastReportActions: ReportActions = {}; +const allSortedReportActions: Record = {}; +let allReportActions: OnyxCollection; +const lastVisibleReportActions: ReportActions = {}; +const filteredReportActionsCache: Record = {}; +const lastMessageTextCache: Record = {}; + +/** + * Invalidates and recomputes cache entries for a specific report. + * This is called when report actions, metadata, or archived status changes. + * + * @param reportID - The ID of the report to invalidate cache for + */ +function invalidateCacheForReport(reportID: string) { + if (!reportID) { + return; + } + + delete lastMessageTextCache[reportID]; + delete filteredReportActionsCache[reportID]; + + if (allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]) { + const reportActionsArray = Object.values(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}); + const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; + const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]); + + let sortedReportActions = getSortedReportActions(withDEWRoutedActionsArray(reportActionsArray), true); + if (transactionThreadReportID) { + const transactionThreadReportActionsArray = Object.values(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`] ?? {}); + sortedReportActions = getCombinedReportActions(sortedReportActions, transactionThreadReportID, transactionThreadReportActionsArray, reportID); + } + allSortedReportActions[reportID] = sortedReportActions; + + const reportNameValuePairs = allReportNameValuePairsOnyxConnect?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`]; + const isReportArchived = !!reportNameValuePairs?.private_isArchived; + const isWriteActionAllowed = canUserPerformWriteAction(report, isReportArchived); + + const reportActionsForDisplay = sortedReportActions.filter( + (reportAction) => + (!(isWhisperAction(reportAction) && !isReportPreviewAction(reportAction) && !isMoneyRequestAction(reportAction)) || isActionableMentionWhisper(reportAction)) && + shouldReportActionBeVisible(reportAction, reportAction.reportActionID, isWriteActionAllowed) && + reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED && + reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + ); + filteredReportActionsCache[reportID] = reportActionsForDisplay; + + const reportActionForDisplay = reportActionsForDisplay.at(0); + if (!reportActionForDisplay) { + delete lastVisibleReportActions[reportID]; + return; + } + lastVisibleReportActions[reportID] = reportActionForDisplay; + + const lastActorAccountID = report?.lastActorAccountID; + let lastActorDetails: Partial | null = lastActorAccountID && allPersonalDetails?.[lastActorAccountID] ? allPersonalDetails[lastActorAccountID] : null; + + if (!lastActorDetails && reportActionForDisplay) { + const lastActorDisplayName = reportActionForDisplay.person?.[0]?.text; + lastActorDetails = lastActorDisplayName + ? { + displayName: lastActorDisplayName, + accountID: lastActorAccountID, + } + : null; + } + } +} + +Onyx.connectWithoutView({ key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (value) => { @@ -239,10 +311,20 @@ Onyx.connect({ }, }); -const lastReportActions: ReportActions = {}; -const allSortedReportActions: Record = {}; -let allReportActions: OnyxCollection; -Onyx.connect({ +Onyx.connectWithoutView({ + key: ONYXKEYS.COLLECTION.REPORT_METADATA, + callback: (value, key) => { + if (!key) { + return; + } + const reportID = key.split('_').at(1); + if (reportID) { + invalidateCacheForReport(reportID); + } + }, +}); + +Onyx.connectWithoutView({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, waitForCollectionCallback: true, callback: (actions) => { @@ -265,7 +347,7 @@ Onyx.connect({ const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`]; - // If the report is a one-transaction report and has , we need to return the combined reportActions so that the LHN can display modifications + // If the report is a one-transaction report, we need to return the combined reportActions so that the LHN can display modifications // to the transaction thread or the report itself const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, actions[reportActions[0]]); if (transactionThreadReportID) { @@ -280,12 +362,13 @@ Onyx.connect({ } else { lastReportActions[reportID] = firstReportAction; } + invalidateCacheForReport(reportID); } }, }); let activePolicyID: OnyxEntry; -Onyx.connect({ +Onyx.connectWithoutView({ key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, callback: (value) => (activePolicyID = value), }); @@ -321,6 +404,27 @@ function getPersonalDetailsForAccountIDs(accountIDs: number[] | undefined, perso return personalDetailsForAccountIDs; } +function getCachedReportActionsForDisplay(reportID: string): ReportAction[] { + return filteredReportActionsCache[reportID] ?? []; +} + +/** + * Get cached last message text for a report, or compute and cache it if missing. + * This uses lazy computation to avoid using deprecated translateLocal in module-level Onyx.connect callbacks. + * + * @param reportID - The report ID to get cached message text for + * @param computeFn - Optional function to compute the message text if cache miss. If provided, result will be cached. + * @returns Cached message text, or undefined if cache miss and no computeFn provided + */ +function getCachedLastMessageText(reportID: string, computeFn?: () => string): string | undefined { + let cached = lastMessageTextCache[reportID]; + if (!cached && computeFn) { + cached = computeFn(); + lastMessageTextCache[reportID] = cached; + } + return cached; +} + /** * Return true if personal details data is ready, i.e. report list options can be created. */ @@ -3216,6 +3320,8 @@ export { getLastActorDisplayName, getLastActorDisplayNameFromLastVisibleActions, getLastMessageTextForReport, + getCachedReportActionsForDisplay, + getCachedLastMessageText, getManagerMcTestParticipant, getMemberInviteOptions, getParticipantsOption, diff --git a/tests/perf-test/SidebarLinks.perf-test.tsx b/tests/perf-test/SidebarLinks.perf-test.tsx index 591294c89ed2..cb23968dd2db 100644 --- a/tests/perf-test/SidebarLinks.perf-test.tsx +++ b/tests/perf-test/SidebarLinks.perf-test.tsx @@ -1,17 +1,11 @@ -import type * as Navigation from '@react-navigation/native'; import {fireEvent, screen, waitFor} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import {measureRenders} from 'reassure'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {OnyxValues} from '@src/ONYXKEYS'; -import type {ReportActions} from '@src/types/onyx'; -import createRandomReportAction from '../utils/collections/reportActions'; -import {createSidebarReportsWithActions as createReportsWithActions} from '../utils/collections/sidebarReports'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; -import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('@libs/Permissions'); @@ -35,22 +29,8 @@ jest.mock('../../src/libs/Navigation/navigationRef', () => ({ isReady: () => true, })); jest.mock('@components/Icon/Expensicons'); -jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); - return { - ...actualNav, - useNavigationState: () => true, - useRoute: jest.fn(), - useFocusEffect: jest.fn(), - useIsFocused: () => true, - useNavigation: () => ({ - navigate: jest.fn(), - addListener: jest.fn(), - }), - createNavigationContainerRef: jest.fn(), - }; -}); +jest.mock('@react-navigation/native'); jest.mock('@src/hooks/useLHNEstimatedListSize/index.native.ts'); const getMockedReportsMap = (length = 100) => { @@ -70,8 +50,6 @@ const getMockedReportsMap = (length = 100) => { const mockedResponseMap = getMockedReportsMap(500); -const REPORTS_COUNT = 150; - describe('SidebarLinks', () => { beforeAll(() => { Onyx.init({ @@ -135,187 +113,4 @@ describe('SidebarLinks', () => { await measureRenders(, {scenario}); }); - - test('[SidebarLinks LHN] initial render with 150 reports and actions', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(REPORTS_COUNT); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - }; - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdatesWithAct(); - - await measureRenders(, {scenario}); - }); - - test('[SidebarLinks LHN] re-render when single report action changes', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(REPORTS_COUNT); - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdates(); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - const firstReportID = '1'; - const actionsCollection = reportActions ?? {}; - const firstReportActions = actionsCollection[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${firstReportID}`]; - if (firstReportActions) { - const newAction = createRandomReportAction(999); - const updatedActions = { - ...firstReportActions, - [`${firstReportID}_999`]: newAction, - }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${firstReportID}`, updatedActions); - await waitForBatchedUpdatesWithAct(); - } - }; - - await measureRenders(, {scenario}); - }); - - test('[SidebarLinks LHN] re-render when multiple reports change', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(REPORTS_COUNT); - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdates(); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - const updates: Record = {}; - const actionsCollection = reportActions ?? {}; - for (let i = 1; i <= 10; i++) { - const reportID = String(i); - const existingActions = actionsCollection[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; - if (existingActions) { - const newAction = createRandomReportAction(1000 + i); - updates[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] = { - ...existingActions, - [`${reportID}_new`]: newAction, - }; - } - } - await Onyx.multiSet(updates as Partial); - await waitForBatchedUpdatesWithAct(); - }; - - await measureRenders(, {scenario}); - }); - - test('[SidebarLinks LHN] re-render when report metadata changes', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(REPORTS_COUNT); - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdates(); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - const firstReportID = '1'; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${firstReportID}`, { - lastVisitTime: new Date().toISOString(), - }); - await waitForBatchedUpdatesWithAct(); - }; - - await measureRenders(, {scenario}); - }); - - test('[SidebarLinks LHN] re-render when report archived status changes', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(REPORTS_COUNT); - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdates(); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - const firstReportID = '1'; - const nameValuePairsCollection = reportNameValuePairs ?? {}; - const currentArchivedStatus = nameValuePairsCollection[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${firstReportID}`]?.private_isArchived; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${firstReportID}`, { - private_isArchived: currentArchivedStatus === 'true' ? 'false' : 'true', - }); - await waitForBatchedUpdatesWithAct(); - }; - - await measureRenders(, {scenario}); - }); - - test('[SidebarLinks LHN] scaling test – initial render with 500 reports', async () => { - const {reports, reportActions, reportNameValuePairs, policies, personalDetails, reportMetadata} = createReportsWithActions(500); - - const scenario = async () => { - await screen.findByTestId('lhn-options-list'); - }; - - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...reports, - ...reportActions, - ...reportNameValuePairs, - ...policies, - ...reportMetadata, - } as Partial); - - await waitForBatchedUpdatesWithAct(); - - await measureRenders(, {scenario}); - }); }); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index f076a3b2a424..8c1af4b6b311 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -3266,7 +3266,7 @@ describe('OptionsListUtils', () => { }, }; await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`, report2); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [movedTransactionAction.reportActionID]: movedTransactionAction, }); await waitForBatchedUpdates(); @@ -3276,12 +3276,13 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: movedTransactionAction, }); expect(lastMessage).toBe(Parser.htmlToText(getMovedTransactionMessage(translateLocal, movedTransactionAction))); }); describe('SUBMITTED action', () => { it('should return automatic submitted message if submitted via harvesting', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(10, undefined), reportID: 'submitted-harvesting'}; const submittedAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED, @@ -3291,7 +3292,7 @@ describe('OptionsListUtils', () => { harvesting: true, }, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [submittedAction.reportActionID]: submittedAction, }); await waitForBatchedUpdates(); @@ -3302,13 +3303,14 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: submittedAction, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallySubmitted'))); }); }); describe('APPROVED action', () => { it('should return automatic approved message if approved automatically', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(11, undefined), reportID: 'approved-auto'}; const approvedAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.APPROVED, @@ -3318,7 +3320,7 @@ describe('OptionsListUtils', () => { automaticAction: true, }, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [approvedAction.reportActionID]: approvedAction, }); await waitForBatchedUpdates(); @@ -3329,13 +3331,14 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: approvedAction, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyApproved'))); }); }); describe('FORWARDED action', () => { it('should return automatic forwarded message if forwarded automatically', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(12, undefined), reportID: 'forwarded-auto'}; const forwardedAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.FORWARDED, @@ -3345,7 +3348,7 @@ describe('OptionsListUtils', () => { automaticAction: true, }, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [forwardedAction.reportActionID]: forwardedAction, }); await waitForBatchedUpdates(); @@ -3356,20 +3359,21 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: forwardedAction, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'iou.automaticallyForwarded'))); }); }); describe('POLICY_CHANGE_LOG.CORPORATE_FORCE_UPGRADE action', () => { it('should return forced corporate upgrade message', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(13, undefined), reportID: 'corporate-force-upgrade'}; const corporateForceUpgradeAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_FORCE_UPGRADE, message: [{type: 'COMMENT', text: ''}], originalMessage: {}, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [corporateForceUpgradeAction.reportActionID]: corporateForceUpgradeAction, }); await waitForBatchedUpdates(); @@ -3380,19 +3384,20 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: corporateForceUpgradeAction, }); expect(lastMessage).toBe(Parser.htmlToText(translate(CONST.LOCALES.EN, 'workspaceActions.forcedCorporateUpgrade'))); }); }); it('TAKE_CONTROL action', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(14, undefined), reportID: 'take-control'}; const takeControlAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL, message: [{type: 'COMMENT', text: ''}], originalMessage: {}, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [takeControlAction.reportActionID]: takeControlAction, }); await waitForBatchedUpdates(); @@ -3402,18 +3407,19 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: takeControlAction, }); expect(lastMessage).toBe(Parser.htmlToText(getChangedApproverActionMessage(translateLocal, takeControlAction))); }); it('REROUTE action', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(15, undefined), reportID: 'reroute'}; const rerouteAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.REROUTE, message: [{type: 'COMMENT', text: ''}], originalMessage: {}, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [rerouteAction.reportActionID]: rerouteAction, }); await waitForBatchedUpdates(); @@ -3423,18 +3429,19 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: rerouteAction, }); expect(lastMessage).toBe(Parser.htmlToText(getChangedApproverActionMessage(translateLocal, rerouteAction))); }); it('MOVED action', async () => { - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(16, undefined), reportID: 'moved-action'}; const movedAction: ReportAction = { ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.MOVED, message: [{type: 'COMMENT', text: ''}], originalMessage: {}, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [movedAction.reportActionID]: movedAction, }); await waitForBatchedUpdates(); @@ -3444,12 +3451,13 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: movedAction, }); expect(lastMessage).toBe(Parser.htmlToText(getMovedActionMessage(translateLocal, movedAction, report))); }); it('DYNAMIC_EXTERNAL_WORKFLOW_ROUTED action', async () => { // Given a DYNAMIC_EXTERNAL_WORKFLOW_ROUTED as the last action - const report: Report = createRandomReport(0, undefined); + const report: Report = {...createRandomReport(17, undefined), reportID: 'dew-routed'}; const action: ReportAction = { reportActionID: '1', created: '', @@ -3457,7 +3465,7 @@ describe('OptionsListUtils', () => { message: [{type: 'COMMENT', text: ''}], originalMessage: {to: 'example@gmail.com'}, }; - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, { [action.reportActionID]: action, }); await waitForBatchedUpdates(); @@ -3469,6 +3477,7 @@ describe('OptionsListUtils', () => { lastActorDetails: null, isReportArchived: false, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: action, }); // Then it should return the DYNAMIC_EXTERNAL_WORKFLOW_ROUTED message @@ -3536,9 +3545,10 @@ describe('OptionsListUtils', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { [submittedAction.reportActionID]: submittedAction, }); + await waitForBatchedUpdates(); const lastMessage = getLastMessageTextForReport({ translate: translateLocal, report, @@ -3548,6 +3558,7 @@ describe('OptionsListUtils', () => { reportMetadata, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: submittedAction, }); expect(lastMessage).toBe(translate(CONST.LOCALES.EN, 'iou.queuedToSubmitViaDEW')); }); @@ -3571,9 +3582,10 @@ describe('OptionsListUtils', () => { }; await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { [dewSubmitFailedAction.reportActionID]: dewSubmitFailedAction, }); + await waitForBatchedUpdates(); const lastMessage = getLastMessageTextForReport({ translate: translateLocal, report, @@ -3581,6 +3593,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: dewSubmitFailedAction, }); expect(lastMessage).toBe(customErrorMessage); }); @@ -3601,9 +3614,10 @@ describe('OptionsListUtils', () => { }; await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { [dewSubmitFailedAction.reportActionID]: dewSubmitFailedAction, }); + await waitForBatchedUpdates(); const lastMessage = getLastMessageTextForReport({ translate: translateLocal, report, @@ -3611,6 +3625,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, visibleReportActionsDataParam: {}, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, + lastAction: dewSubmitFailedAction, }); expect(lastMessage).toBe(translate(CONST.LOCALES.EN, 'iou.error.genericCreateFailureMessage')); }); diff --git a/tests/utils/collections/sidebarReports.ts b/tests/utils/collections/sidebarReports.ts index 29439b726408..857177490b90 100644 --- a/tests/utils/collections/sidebarReports.ts +++ b/tests/utils/collections/sidebarReports.ts @@ -3,12 +3,8 @@ import type {OnyxCollection} from 'react-native-onyx'; import type {ReportsToDisplayInLHN} from '@hooks/useSidebarOrderedReports'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, Report, ReportActions, ReportAttributesDerivedValue, ReportMetadata, ReportNameValuePairs} from '@src/types/onyx'; -import type Policy from '@src/types/onyx/Policy'; +import type {Report, ReportAttributesDerivedValue, ReportNameValuePairs} from '@src/types/onyx'; import createCollection from './createCollection'; -import createPersonalDetails from './personalDetails'; -import createRandomPolicy from './policies'; -import createRandomReportAction from './reportActions'; import {createRandomReport} from './reports'; /** @@ -134,74 +130,4 @@ function createSidebarTestData(): { }; } -const LHN_ACTIONS_PER_REPORT = 50; - -function createSidebarReportActions(reportID: string, count: number): ReportActions { - const actions: ReportActions = {}; - for (let i = 0; i < count; i++) { - actions[`${reportID}_${i}`] = createRandomReportAction(i); - } - return actions; -} - -function createSidebarReportsWithActions(count: number): { - reports: OnyxCollection; - reportActions: OnyxCollection; - reportNameValuePairs: OnyxCollection; - policies: OnyxCollection; - personalDetails: OnyxCollection; - reportMetadata: OnyxCollection; -} { - const reports: OnyxCollection = {}; - const reportActions: OnyxCollection = {}; - const reportNameValuePairs: OnyxCollection = {}; - const policies: OnyxCollection = {}; - const personalDetails: OnyxCollection = {}; - const reportMetadata: OnyxCollection = {}; - - const basePolicy = createRandomPolicy(1); - policies[`${ONYXKEYS.COLLECTION.POLICY}${basePolicy.id}`] = basePolicy; - - for (let i = 1; i <= count; i++) { - const reportID = String(i); - const report = createRandomReport(i, undefined); - - const isArchived = i % 10 === 0; - const reportTypeMod = i % 4; - let reportType: Report['type'] = CONST.REPORT.TYPE.CHAT; - if (reportTypeMod === 0) { - reportType = CONST.REPORT.TYPE.IOU; - } else if (reportTypeMod === 1) { - reportType = CONST.REPORT.TYPE.EXPENSE; - } - - reports[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] = { - ...report, - type: reportType, - }; - reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] = createSidebarReportActions(reportID, LHN_ACTIONS_PER_REPORT); - reportNameValuePairs[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`] = { - private_isArchived: isArchived ? 'true' : 'false', - }; - - const lastActorAccountID = report.lastActorAccountID ?? i; - personalDetails[String(lastActorAccountID)] = createPersonalDetails(lastActorAccountID); - - if (i % 5 === 0) { - reportMetadata[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`] = { - lastVisitTime: new Date().toISOString(), - }; - } - } - - return { - reports, - reportActions, - reportNameValuePairs, - policies, - personalDetails, - reportMetadata, - }; -} - -export {createSidebarReport, createSidebarReportsCollection, createSidebarTestData, createSidebarReportsWithActions}; +export {createSidebarReport, createSidebarReportsCollection, createSidebarTestData};