From 78203a0afc49760c28f73de07c37104bccf933a6 Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Sat, 4 Jul 2026 10:57:43 +0700 Subject: [PATCH 1/2] Update related components and tests to ensure consistent translation handling across invoice and report naming functionalities. --- .../usePreviewMessageAnimation.ts | 2 +- src/libs/ReportNameUtils.ts | 60 ++++++++++++------- src/libs/ReportUtils.ts | 6 +- .../OnyxDerived/configs/reportAttributes.ts | 5 ++ src/pages/inbox/report/SearchActionHeader.tsx | 2 +- tests/unit/ReportNameUtilsTest.ts | 45 ++++++++++++-- tests/unit/ReportUtilsTest.ts | 9 +-- 7 files changed, 96 insertions(+), 33 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestReportPreview/usePreviewMessageAnimation.ts b/src/components/ReportActionItem/MoneyRequestReportPreview/usePreviewMessageAnimation.ts index caf1b2be9b45..cfa0cd603b28 100644 --- a/src/components/ReportActionItem/MoneyRequestReportPreview/usePreviewMessageAnimation.ts +++ b/src/components/ReportActionItem/MoneyRequestReportPreview/usePreviewMessageAnimation.ts @@ -125,7 +125,7 @@ function usePreviewMessageAnimation({ if (isPolicyExpenseChat || isTripRoom) { payerOrApproverName = getPolicyName({report: chatReport, policy, unavailableTranslation: translate('workspace.common.unavailable')}); } else if (isInvoiceRoom) { - payerOrApproverName = getInvoicePayerName(chatReport, invoiceReceiverPolicy, invoiceReceiverPersonalDetail); + payerOrApproverName = getInvoicePayerName(chatReport, translate, invoiceReceiverPolicy, invoiceReceiverPersonalDetail); } else { payerOrApproverName = getDisplayNameForParticipant({ accountID: managerID, diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 1ab62a5f5a11..c5576ec3e8b0 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -32,7 +32,7 @@ import {translateLocal} from './Localize'; // eslint-disable-next-line import/no-cycle import {getForReportAction, getMovedReportID} from './ModifiedExpenseMessage'; import Parser from './Parser'; -import {getDisplayNameOrDefault} from './PersonalDetailsUtils'; +import {temporaryGetDisplayNameOrDefault} from './PersonalDetailsUtils'; import {getCleanedTagName, isPolicyAdmin, isPolicyFieldListEmpty} from './PolicyUtils'; import { getActionableCard3DSTransactionApprovalMessage, @@ -186,6 +186,7 @@ type ComputeReportName = { reportActions?: OnyxCollection; currentUserAccountID?: number; currentUserLogin: string; + translate: LocalizedTranslate; // TODO: Make this required when https://github.com/Expensify/App/issues/66411 is done conciergeReportID?: string; reportAttributes?: ReportAttributesDerivedValue['reports']; @@ -327,12 +328,14 @@ function getInvoicesChatName({ personalDetails, policy, currentUserAccountID, + translate, }: { report: OnyxEntry; receiverPolicy: OnyxEntry; personalDetails?: Partial; policy: OnyxEntry; currentUserAccountID?: number; + translate: LocalizedTranslate; }): string { const invoiceReceiver = report?.invoiceReceiver; const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL; @@ -344,14 +347,14 @@ function getInvoicesChatName({ } if (isIndividual) { - return formatPhoneNumberPhoneUtils(getDisplayNameOrDefault((personalDetails ?? allPersonalDetails)?.[invoiceReceiverAccountID])); + return formatPhoneNumberPhoneUtils(temporaryGetDisplayNameOrDefault({passedPersonalDetails: (personalDetails ?? allPersonalDetails)?.[invoiceReceiverAccountID], translate})); } return getPolicyName({report, policy: receiverPolicy}); } -function getInvoiceReportName(report: OnyxEntry, policy?: OnyxEntry, invoiceReceiverPolicy?: OnyxEntry): string { - const moneyRequestReportName = getMoneyRequestReportName({report, policy, invoiceReceiverPolicy}); +function getInvoiceReportName(report: OnyxEntry, translate: LocalizedTranslate, policy?: OnyxEntry, invoiceReceiverPolicy?: OnyxEntry): string { + const moneyRequestReportName = getMoneyRequestReportName({report, policy, invoiceReceiverPolicy, translate}); const oldDotInvoiceName = report?.reportName ?? moneyRequestReportName; return isNewDotInvoice(report?.chatReportID) ? moneyRequestReportName : oldDotInvoiceName; } @@ -361,13 +364,18 @@ function getInvoiceReportName(report: OnyxEntry, policy?: OnyxEntry, invoiceReceiverPolicy?: OnyxEntry, invoiceReceiverPersonalDetail?: PersonalDetails | null): string { +function getInvoicePayerName( + report: OnyxEntry, + translate: LocalizedTranslate, + invoiceReceiverPolicy?: OnyxEntry, + invoiceReceiverPersonalDetail?: PersonalDetails | null, +): string { const invoiceReceiver = report?.invoiceReceiver; const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL; if (isIndividual) { const personalDetail = invoiceReceiverPersonalDetail ?? allPersonalDetails?.[invoiceReceiver.accountID]; - return formatPhoneNumberPhoneUtils(getDisplayNameOrDefault(personalDetail ?? undefined)); + return formatPhoneNumberPhoneUtils(temporaryGetDisplayNameOrDefault({passedPersonalDetails: personalDetail ?? undefined, translate})); } return getPolicyName({report, policy: invoiceReceiverPolicy}); @@ -376,7 +384,17 @@ function getInvoicePayerName(report: OnyxEntry, invoiceReceiverPolicy?: /** * Get the title for an IOU or expense chat which will be showing the payer and the amount */ -function getMoneyRequestReportName({report, policy, invoiceReceiverPolicy}: {report: OnyxEntry; policy?: OnyxEntry; invoiceReceiverPolicy?: OnyxEntry}): string { +function getMoneyRequestReportName({ + report, + policy, + invoiceReceiverPolicy, + translate, +}: { + report: OnyxEntry; + policy?: OnyxEntry; + invoiceReceiverPolicy?: OnyxEntry; + translate: LocalizedTranslate; +}): string { // For expense reports with empty fieldList and empty reportName, return "New Report" (matches OldDot behavior) if (isExpenseReport(report)) { if (report?.reportName === '' && isPolicyFieldListEmpty(policy)) { @@ -397,27 +415,27 @@ function getMoneyRequestReportName({report, policy, invoiceReceiverPolicy}: {rep payerOrApproverName = getPolicyName({report: parentReport ?? report, policy}); } else if (isInvoiceReport(report)) { const chatReport = getReportOrDraftReport(report?.chatReportID); - payerOrApproverName = getInvoicePayerName(chatReport, invoiceReceiverPolicy); + payerOrApproverName = getInvoicePayerName(chatReport, translate, invoiceReceiverPolicy); } else { payerOrApproverName = getDisplayNameForParticipant({accountID: report?.managerID, formatPhoneNumber: formatPhoneNumberPhoneUtils}) ?? ''; } - const payerPaidAmountMessage = translateLocal('iou.payerPaidAmount', formattedAmount, payerOrApproverName); + const payerPaidAmountMessage = translate('iou.payerPaidAmount', formattedAmount, payerOrApproverName); if (isReportApproved({report})) { - return translateLocal('iou.managerApprovedAmount', payerOrApproverName, formattedAmount); + return translate('iou.managerApprovedAmount', payerOrApproverName, formattedAmount); } if (report?.isWaitingOnBankAccount) { - return `${payerPaidAmountMessage} ${CONST.DOT_SEPARATOR} ${translateLocal('iou.pending')}`; + return `${payerPaidAmountMessage} ${CONST.DOT_SEPARATOR} ${translate('iou.pending')}`; } if (!isSettled(report?.reportID) && hasNonReimbursableTransactions(report?.reportID)) { payerOrApproverName = getDisplayNameForParticipant({accountID: report?.ownerAccountID, formatPhoneNumber: formatPhoneNumberPhoneUtils}) ?? ''; - return translateLocal('iou.payerSpentAmount', formattedAmount, payerOrApproverName); + return translate('iou.payerSpentAmount', formattedAmount, payerOrApproverName); } if (isProcessingReport(report) || isOpenExpenseReport(report) || isOpenInvoiceReport(report) || moneyRequestTotal === 0) { - return translateLocal('iou.payerOwesAmount', formattedAmount, payerOrApproverName); + return translate('iou.payerOwesAmount', formattedAmount, payerOrApproverName); } return payerPaidAmountMessage; @@ -930,6 +948,7 @@ function computeReportName({ reportActions, currentUserAccountID, currentUserLogin, + translate, allPolicyTags, conciergeReportID, reportAttributes, @@ -944,7 +963,7 @@ function computeReportName({ const parentReportAction = isThread(report) ? reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID}`]?.[report.parentReportActionID] : undefined; const parentReportActionBasedName = computeReportNameBasedOnReportAction( - translateLocal, + translate, formatPhoneNumberPhoneUtils, parentReportAction, report, @@ -976,11 +995,12 @@ function computeReportName({ reportActions, currentUserAccountID, currentUserLogin, + translate, conciergeReportID, reportAttributes, isTrackIntentUser, }); - return getCreatedReportForUnapprovedTransactionsMessage(originalID, reportName, isOriginalReportDeleted(parentReportAction, originalReport), translateLocal); + return getCreatedReportForUnapprovedTransactionsMessage(originalID, reportName, isOriginalReportDeleted(parentReportAction, originalReport), translate); } if (isTaskReport(report)) { @@ -993,7 +1013,7 @@ function computeReportName({ const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`]; const chatThreadReportName = computeChatThreadReportName( - translateLocal, + translate, privateIsArchivedValue, report, reports ?? {}, @@ -1009,7 +1029,7 @@ function computeReportName({ const transactionsArray = transactions ? (Object.values(transactions).filter(Boolean) as Array>) : undefined; if (isClosedExpenseReportWithNoExpenses(report, transactionsArray)) { - return translateLocal('parentReportAction.deletedReport'); + return translate('parentReportAction.deletedReport'); } if (isGroupChat(report)) { @@ -1028,7 +1048,7 @@ function computeReportName({ const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; if (isMoneyRequestReport(report)) { - formattedName = getMoneyRequestReportName({report, policy}); + formattedName = getMoneyRequestReportName({report, policy, translate}); } if (isInvoiceReport(report)) { @@ -1039,7 +1059,7 @@ function computeReportName({ chatReceiverPolicyID = (chatReceiver as {policyID: string}).policyID; } const invoiceReceiverPolicy = chatReceiverPolicyID ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${chatReceiverPolicyID}`] : undefined; - formattedName = getInvoiceReportName(report, policy, invoiceReceiverPolicy); + formattedName = getInvoiceReportName(report, translate, policy, invoiceReceiverPolicy); } if (isInvoiceRoom(report)) { @@ -1049,7 +1069,7 @@ function computeReportName({ receiverPolicyID = (receiver as {policyID: string}).policyID; } const invoiceReceiverPolicy = receiverPolicyID ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${receiverPolicyID}`] : undefined; - formattedName = getInvoicesChatName({report, receiverPolicy: invoiceReceiverPolicy, personalDetails: personalDetailsList, currentUserAccountID, policy}); + formattedName = getInvoicesChatName({report, receiverPolicy: invoiceReceiverPolicy, personalDetails: personalDetailsList, currentUserAccountID, policy, translate}); } if (isSelfDM(report)) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2c440fcec374..26c700925f81 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6084,7 +6084,7 @@ function getParentNavigationSubtitle( const invoiceReceiverPolicyID = getInvoiceReceiverPolicyID(parentReport); const invoiceReceiverPolicy = invoiceReceiverPolicyID ? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`] : undefined; const isCurrentUserReceiver = isCurrentUserInvoiceReceiver(parentReport); - const invoicePayerName = getInvoicePayerName(parentReport, invoiceReceiverPolicy); + const invoicePayerName = getInvoicePayerName(parentReport, translate, invoiceReceiverPolicy); let reportName = senderWorkspaceName; if (!isCurrentUserReceiver && invoicePayerName) { @@ -12721,12 +12721,12 @@ function isWaitingForSubmissionFromCurrentUser(chatReport: OnyxEntry, po return chatReport?.isOwnPolicyExpenseChat && !policy?.harvesting?.enabled; } -function getChatListItemReportName(action: ReportAction & {reportName?: string}, report: Report | undefined, conciergeReportID: string | undefined): string { +function getChatListItemReportName(action: ReportAction & {reportName?: string}, report: Report | undefined, conciergeReportID: string | undefined, translate: LocalizedTranslate): string { if (report && isInvoiceReport(report)) { const properInvoiceReport = report; properInvoiceReport.chatReportID = report.parentReportID; - return getInvoiceReportName(properInvoiceReport); + return getInvoiceReportName(properInvoiceReport, translate); } if (action?.reportName) { diff --git a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts index cb6baae3b80b..3156fc2ed8df 100644 --- a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts +++ b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts @@ -1,3 +1,6 @@ +import type {LocalizedTranslate} from '@components/LocaleContextProvider'; + +import {translate as translateForLocale} from '@libs/Localize'; import {getIsOffline} from '@libs/NetworkState'; import {getLinkedTransactionID} from '@libs/ReportActionsUtils'; import {computeReportName} from '@libs/ReportNameUtils'; @@ -118,6 +121,7 @@ export default createOnyxDerivedValueConfig({ ) => { // Read the in-memory offline state directly (NETWORK is a dependency so recompute still fires when it changes). const isOffline = getIsOffline(); + const translate: LocalizedTranslate = (path, ...parameters) => translateForLocale(preferredLocale, path, ...parameters); // Check if display names changed when personal details are updated let displayNamesChanged = false; if (hasKeyTriggeredCompute(ONYXKEYS.PERSONAL_DETAILS_LIST, sourceValues)) { @@ -373,6 +377,7 @@ export default createOnyxDerivedValueConfig({ reportActions, currentUserAccountID: session?.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserLogin: session?.email ?? '', + translate, allPolicyTags: policyTags, conciergeReportID: conciergeReportID ?? undefined, reportAttributes: currentValue?.reports, diff --git a/src/pages/inbox/report/SearchActionHeader.tsx b/src/pages/inbox/report/SearchActionHeader.tsx index 1182d411911d..4e04c353553a 100644 --- a/src/pages/inbox/report/SearchActionHeader.tsx +++ b/src/pages/inbox/report/SearchActionHeader.tsx @@ -36,7 +36,7 @@ function SearchActionHeaderContent({action, report, isWhisper, onPress, children const {translate} = useLocalize(); const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); - const reportName = getChatListItemReportName(action, report, conciergeReportID); + const reportName = getChatListItemReportName(action, report, conciergeReportID, translate); return ( diff --git a/tests/unit/ReportNameUtilsTest.ts b/tests/unit/ReportNameUtilsTest.ts index 92d865685a17..a3a9c0f22320 100644 --- a/tests/unit/ReportNameUtilsTest.ts +++ b/tests/unit/ReportNameUtilsTest.ts @@ -1,3 +1,5 @@ +import type {LocalizedTranslate} from '@components/LocaleContextProvider'; + import {translate} from '@libs/Localize'; import { buildReportNameFromParticipantNames, @@ -24,7 +26,7 @@ import createRandomPolicy from '../utils/collections/policies'; import {createAdminRoom, createExpenseReport, createPolicyExpenseChat, createRegularChat, createRegularTaskReport, createSelfDM, createWorkspaceThread} from '../utils/collections/reports'; import createRandomTransaction from '../utils/collections/transaction'; import {fakePersonalDetails} from '../utils/LHNTestUtils'; -import {formatPhoneNumber} from '../utils/TestHelper'; +import {formatPhoneNumber, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const currentUserLogin = 'lagertha2@vikings.net'; @@ -50,6 +52,7 @@ describe('ReportNameUtils', () => { reportActions, currentUserAccountID: currentUserID, currentUserLogin, + translate: translateLocal, isTrackIntentUser: false, }); const participantsPersonalDetails: PersonalDetailsList = [ @@ -560,6 +563,7 @@ describe('ReportNameUtils', () => { reportActions: reportActionsCollection, currentUserAccountID, currentUserLogin: '', + translate: translateLocal, allPolicyTags: policyTagsCollection, isTrackIntentUser: false, }); @@ -1052,6 +1056,7 @@ describe('ReportNameUtils', () => { personalDetails: participantsPersonalDetails, policy: undefined, currentUserAccountID, + translate: translateLocal, }); expect(name).toBe('Personal Workspace'); @@ -1071,6 +1076,7 @@ describe('ReportNameUtils', () => { personalDetails: participantsPersonalDetails, policy: undefined, currentUserAccountID, + translate: translateLocal, }); const normalizedName = name?.replaceAll('\u00A0', ' '); @@ -1082,11 +1088,42 @@ describe('ReportNameUtils', () => { reportID: 'invoice-chat-3', invoiceReceiver: {type: CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL, accountID: 1}, }; - const name = getInvoicePayerName(report, undefined, null); + const name = getInvoicePayerName(report, translateLocal, undefined, null); const normalizedName = name?.replaceAll('\u00A0', ' '); expect(normalizedName).toBe('Ragnar Lothbrok'); }); + + test('Invoice room resolves the hidden fallback through the provided translate function', () => { + const translateWithHiddenMarker: LocalizedTranslate = (path, ...parameters) => (path === 'common.hidden' ? 'HiddenMarker' : translateLocal(path, ...parameters)); + const report: Report = { + reportID: 'invoice-chat-4', + invoiceReceiver: {type: CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL, accountID: 424242}, + }; + + const name = getInvoicesChatName({ + report, + receiverPolicy: undefined, + personalDetails: {}, + policy: undefined, + currentUserAccountID, + translate: translateWithHiddenMarker, + }); + + expect(name).toBe('HiddenMarker'); + }); + + test('Invoice payer name resolves the hidden fallback through the provided translate function', () => { + const translateWithHiddenMarker: LocalizedTranslate = (path, ...parameters) => (path === 'common.hidden' ? 'HiddenMarker' : translateLocal(path, ...parameters)); + const report: Report = { + reportID: 'invoice-chat-5', + invoiceReceiver: {type: CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL, accountID: 424242}, + }; + + const name = getInvoicePayerName(report, translateWithHiddenMarker, undefined, null); + + expect(name).toBe('HiddenMarker'); + }); }); describe('getPolicyExpenseChatName', () => { @@ -1248,7 +1285,7 @@ describe('ReportNameUtils', () => { }; // When we get the money request report name - const reportName = getMoneyRequestReportName({report: expenseReport, policy: policyWithEmptyFieldList}); + const reportName = getMoneyRequestReportName({report: expenseReport, policy: policyWithEmptyFieldList, translate: translateLocal}); // Then it should return "New Report" expect(reportName).toBe(CONST.REPORT.DEFAULT_EXPENSE_REPORT_NAME); @@ -1290,7 +1327,7 @@ describe('ReportNameUtils', () => { }; // When we get the money request report name - const reportName = getMoneyRequestReportName({report: expenseReport, policy: policyWithFieldList}); + const reportName = getMoneyRequestReportName({report: expenseReport, policy: policyWithFieldList, translate: translateLocal}); // Then it should NOT return empty string — it should fall through to dynamic name computation expect(reportName).not.toBe(''); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 7402d515eb1f..aea99aa260b8 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -320,6 +320,7 @@ const computeReportName = ( reportActions, currentUserAccountID: currentUserID, currentUserLogin: currentUserEmail, + translate: translateLocal, conciergeReportID, isTrackIntentUser: false, }); @@ -18413,7 +18414,7 @@ describe('ReportUtils', () => { await waitForBatchedUpdates(); const action = {...createRandomReportAction(1)}; - const result = getChatListItemReportName(action, conciergeReport, conciergeReportID); + const result = getChatListItemReportName(action, conciergeReport, conciergeReportID, translateLocal); expect(result).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); @@ -18427,7 +18428,7 @@ describe('ReportUtils', () => { await waitForBatchedUpdates(); const action = {...createRandomReportAction(2)}; - const result = getChatListItemReportName(action, regularReport, conciergeReportID); + const result = getChatListItemReportName(action, regularReport, conciergeReportID, translateLocal); expect(result).not.toBe(CONST.CONCIERGE_DISPLAY_NAME); }); @@ -18437,7 +18438,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.CHAT, }; const action = {...createRandomReportAction(3), reportName: 'Custom Action Name'}; - const result = getChatListItemReportName(action, conciergeReport, conciergeReportID); + const result = getChatListItemReportName(action, conciergeReport, conciergeReportID, translateLocal); expect(result).toBe('Custom Action Name'); }); @@ -18451,7 +18452,7 @@ describe('ReportUtils', () => { await waitForBatchedUpdates(); const action = {...createRandomReportAction(4)}; - const result = getChatListItemReportName(action, conciergeReport, undefined); + const result = getChatListItemReportName(action, conciergeReport, undefined, translateLocal); expect(result).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); }); From a090994b5f3523160d5de96b30a8d6c7cf940e2b Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Sat, 4 Jul 2026 11:09:38 +0700 Subject: [PATCH 2/2] Add tests for invoice report name --- tests/unit/ReportUtilsTest.ts | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index aea99aa260b8..9a41c173af2b 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -1,8 +1,8 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {beforeAll} from '@jest/globals'; import {act, renderHook} from '@testing-library/react-native'; -import type {LocaleContextProps} from '@components/LocaleContextProvider'; +/* eslint-disable @typescript-eslint/naming-convention */ +import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; import type PolicyData from '@hooks/usePolicyData/types'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -18455,6 +18455,38 @@ describe('ReportUtils', () => { const result = getChatListItemReportName(action, conciergeReport, undefined, translateLocal); expect(result).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); + + it('should compute the invoice report name through the provided translate function', () => { + const invoiceReport: Report = { + reportID: 'invoice-report-789', + type: CONST.REPORT.TYPE.INVOICE, + parentReportID: 'invoice-chat-123', + currency: 'USD', + }; + // An invoice report without transactions has a total of zero, so its name resolves to the + // "payer owes" message, which must come from the translate function passed by the caller. + const translateWithMarker: LocalizedTranslate = (path, ...parameters) => (path === 'iou.payerOwesAmount' ? 'PayerOwesMarker' : translateLocal(path, ...parameters)); + + const action = {...createRandomReportAction(5)}; + const result = getChatListItemReportName(action, invoiceReport, undefined, translateWithMarker); + + expect(result).toBe('PayerOwesMarker'); + }); + + it('should return the stored reportName for OldDot invoice reports', () => { + const invoiceReport: Report = { + reportID: 'invoice-report-790', + type: CONST.REPORT.TYPE.INVOICE, + parentReportID: 'invoice-chat-124', + reportName: 'Invoice #42', + currency: 'USD', + }; + + const action = {...createRandomReportAction(6)}; + const result = getChatListItemReportName(action, invoiceReport, undefined, translateLocal); + + expect(result).toBe('Invoice #42'); + }); }); describe('buildOptimisticApprovedReportAction', () => { it('should set actorAccountID to the provided currentUserAccountID', () => {