From 132a7ce7f2d2af5a492857b9c24465a08fcc764d Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 19 Apr 2025 11:10:38 +0800 Subject: [PATCH 1/3] delete the expense/iou report when deleting the last transaction --- src/libs/actions/IOU.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index be0aa0282160..f2f6af99153f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7019,9 +7019,8 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT if (chatReport) { canUserPerformWriteAction = !!canUserPerformWriteActionReportUtils(chatReport); } - const lastVisibleAction = getLastVisibleAction(iouReport?.reportID, canUserPerformWriteAction, updatedReportAction); - const iouReportLastMessageText = getLastVisibleMessage(iouReport?.reportID, canUserPerformWriteAction, updatedReportAction).lastMessageText; - const shouldDeleteIOUReport = iouReportLastMessageText.length === 0 && !isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread); + // If we are deleting the last transaction on a report, then delete the report too + const shouldDeleteIOUReport = getReportTransactions(iouReportID).length === 1; // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxInputValue; @@ -7063,6 +7062,8 @@ function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxT } if (updatedIOUReport) { + const lastVisibleAction = getLastVisibleAction(iouReport?.reportID, canUserPerformWriteAction, updatedReportAction); + const iouReportLastMessageText = getLastVisibleMessage(iouReport?.reportID, canUserPerformWriteAction, updatedReportAction).lastMessageText; updatedIOUReport.lastMessageText = iouReportLastMessageText; updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created; } From b31f450bb82ee9de261131b34a819baf390b37b2 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 19 Apr 2025 11:37:42 +0800 Subject: [PATCH 2/3] lint --- src/libs/actions/IOU.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f2f6af99153f..d56c0d2ffcba 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -84,7 +84,6 @@ import { getTrackExpenseActionableWhisper, isActionableTrackExpense, isCreatedAction, - isDeletedParentAction, isMoneyRequestAction, isReportPreviewAction, } from '@libs/ReportActionsUtils'; From c2235c9aad130bd089dbc3d446db09fdee63dfa7 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 19 Apr 2025 11:38:09 +0800 Subject: [PATCH 3/3] update test --- tests/actions/IOUTest.ts | 113 +++++++++++++-------------------------- 1 file changed, 37 insertions(+), 76 deletions(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index ea0559ca67c1..d3c805c4d097 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -2813,7 +2813,7 @@ describe('actions/IOU', () => { expect(tr).toBeFalsy(); }); - it('delete the IOU report when there are no visible comments left in the IOU report', async () => { + it('delete the IOU report when there are no expenses left in the IOU report', async () => { // Given an IOU report and a paused fetch state mockFetch?.pause?.(); @@ -2856,41 +2856,27 @@ describe('actions/IOU', () => { expect(report).toBeFalsy(); }); - it('does not delete the IOU report when there are visible comments left in the IOU report', async () => { - // Given the initial setup is completed - await waitForBatchedUpdates(); - - Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${IOU_REPORT_ID}`, - callback: (val) => (reportActions = val), + it('does not delete the IOU report when there are expenses left in the IOU report', async () => { + // Given multiple expenses on an IOU report + requestMoney({ + report: chatReport, + participantParams: { + payeeEmail: TEST_USER_LOGIN, + payeeAccountID: TEST_USER_ACCOUNT_ID, + participant: {login: RORY_EMAIL, accountID: RORY_ACCOUNT_ID}, + }, + transactionParams: { + amount, + attendees: [], + currency: CONST.CURRENCY.USD, + created: '', + merchant: '', + comment, + }, }); - await waitForBatchedUpdates(); - - jest.advanceTimersByTime(10); - - // When a comment is added to the IOU report - if (IOU_REPORT_ID) { - addComment(IOU_REPORT_ID, 'Testing a comment'); - } - await waitForBatchedUpdates(); - - // Then verify that the comment is correctly added - const resultAction = Object.values(reportActions ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT); - reportActionID = resultAction?.reportActionID; - - expect(resultAction?.message).toEqual(REPORT_ACTION.message); - expect(resultAction?.person).toEqual(REPORT_ACTION.person); - expect(resultAction?.pendingAction).toBeUndefined(); await waitForBatchedUpdates(); - // Verify there are three actions (created + iou + addcomment) and our optimistic comment has been removed - expect(Object.values(reportActions ?? {}).length).toBe(3); - - // Then check the loading state of our action - const resultActionAfterUpdate = reportActionID ? reportActions?.[reportActionID] : undefined; - expect(resultActionAfterUpdate?.pendingAction).toBeUndefined(); - // When we attempt to delete an expense from the IOU report mockFetch?.pause?.(); if (transaction && createIOUAction) { @@ -2918,7 +2904,7 @@ describe('actions/IOU', () => { expect(iouReport).toHaveProperty('chatReportID'); // Given the resumed fetch state - mockFetch?.resume?.(); + await mockFetch?.resume?.(); allReports = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -3449,49 +3435,31 @@ describe('actions/IOU', () => { }); it('navigate the user correctly to the iou Report when appropriate', async () => { - await waitForBatchedUpdates(); - - Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${IOU_REPORT_ID}`, - callback: (val) => (reportActions = val), + // Given multiple expenses on an IOU report + requestMoney({ + report: chatReport, + participantParams: { + payeeEmail: TEST_USER_LOGIN, + payeeAccountID: TEST_USER_ACCOUNT_ID, + participant: {login: RORY_EMAIL, accountID: RORY_ACCOUNT_ID}, + }, + transactionParams: { + amount, + attendees: [], + currency: CONST.CURRENCY.USD, + created: '', + merchant: '', + comment, + }, }); await waitForBatchedUpdates(); - // Given an added comment to the iou report - - jest.advanceTimersByTime(10); - - if (IOU_REPORT_ID) { - addComment(IOU_REPORT_ID, 'Testing a comment'); - } - await waitForBatchedUpdates(); - - const resultAction = Object.values(reportActions ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT); - reportActionID = resultAction?.reportActionID; - - expect(resultAction?.message).toEqual(REPORT_ACTION.message); - expect(resultAction?.person).toEqual(REPORT_ACTION.person); - - await waitForBatchedUpdates(); - - // Verify there are three actions (created + iou + addcomment) and our optimistic comment has been removed - expect(Object.values(reportActions ?? {}).length).toBe(3); - - await waitForBatchedUpdates(); - // Given a thread report - jest.advanceTimersByTime(10); thread = buildTransactionThread(createIOUAction, iouReport); expect(thread.participants).toStrictEqual({[CARLOS_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, role: CONST.REPORT.ROLE.ADMIN}}); - Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${thread.reportID}`, - callback: (val) => (reportActions = val), - }); - await waitForBatchedUpdates(); - jest.advanceTimersByTime(10); const participantAccountIDs = Object.keys(thread.participants ?? {}).map(Number); const userLogins = getLoginsByAccountIDs(participantAccountIDs); @@ -3515,17 +3483,13 @@ describe('actions/IOU', () => { ); expect(createIOUAction?.childReportID).toBe(thread.reportID); - await waitForBatchedUpdates(); - - // When we delete the expense in SingleTransactionView and we should not delete the IOU report - + // When we delete the expense, we should not delete the IOU report mockFetch?.pause?.(); let navigateToAfterDelete; if (transaction && createIOUAction) { navigateToAfterDelete = deleteMoneyRequest(transaction.transactionID, createIOUAction, true); } - await waitForBatchedUpdates(); let allReports = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -3538,14 +3502,12 @@ describe('actions/IOU', () => { }); }); - await waitForBatchedUpdates(); - iouReport = Object.values(allReports ?? {}).find((report) => isIOUReport(report)); expect(iouReport).toBeTruthy(); expect(iouReport).toHaveProperty('reportID'); expect(iouReport).toHaveProperty('chatReportID'); - mockFetch?.resume?.(); + await mockFetch?.resume?.(); allReports = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -3564,7 +3526,6 @@ describe('actions/IOU', () => { expect(iouReport).toHaveProperty('chatReportID'); // Then we expect to navigate to the iou report - expect(IOU_REPORT_ID).not.toBeUndefined(); if (IOU_REPORT_ID) { expect(navigateToAfterDelete).toEqual(ROUTES.REPORT_WITH_ID.getRoute(IOU_REPORT_ID));