diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js
index fc189a3aef36..fc38b102b8e8 100644
--- a/src/pages/home/report/ReportActionItemSingle.js
+++ b/src/pages/home/report/ReportActionItemSingle.js
@@ -122,7 +122,10 @@ function ReportActionItemSingle(props) {
id: secondaryAccountId,
};
} else if (!isWorkspaceActor) {
- secondaryAvatar = ReportUtils.getIcons(props.report, {})[props.report.isOwnPolicyExpenseChat ? 0 : 1];
+ const avatarIconIndex = props.report.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(props.report) ? 0 : 1;
+ const reportIcons = ReportUtils.getIcons(props.report, {});
+
+ secondaryAvatar = reportIcons[avatarIconIndex];
}
const icon = {source: avatarSource, type: isWorkspaceActor ? CONST.ICON_TYPE_WORKSPACE : CONST.ICON_TYPE_AVATAR, name: primaryDisplayName, id: isWorkspaceActor ? '' : actorAccountID};
diff --git a/tests/unit/ReportActionItemSingleTest.js b/tests/unit/ReportActionItemSingleTest.js
new file mode 100644
index 000000000000..d6b46eb55414
--- /dev/null
+++ b/tests/unit/ReportActionItemSingleTest.js
@@ -0,0 +1,86 @@
+import Onyx from 'react-native-onyx';
+import {cleanup, screen} from '@testing-library/react-native';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
+
+const ONYXKEYS = {
+ PERSONAL_DETAILS_LIST: 'personalDetailsList',
+ IS_LOADING_REPORT_DATA: 'isLoadingReportData',
+ COLLECTION: {
+ REPORT_ACTIONS: 'reportActions_',
+ POLICY: 'policy_',
+ },
+ NETWORK: 'network',
+};
+
+describe('ReportActionItemSingle', () => {
+ beforeAll(() =>
+ Onyx.init({
+ keys: ONYXKEYS,
+ registerStorageEventListener: () => {},
+ safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
+ }),
+ );
+
+ beforeEach(() => {
+ // Wrap Onyx each onyx action with waitForBatchedUpdates
+ wrapOnyxWithWaitForBatchedUpdates(Onyx);
+ // Initialize the network key for OfflineWithFeedback
+ return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false});
+ });
+
+ // Clear out Onyx after each test so that each test starts with a clean slate
+ afterEach(() => {
+ cleanup();
+ Onyx.clear();
+ });
+
+ describe('when the Report is a policy expense chat', () => {
+ describe('and the property "shouldShowSubscriptAvatar" is true', () => {
+ const shouldShowSubscriptAvatar = true;
+ const fakeReport = LHNTestUtils.getFakeReportWithPolicy([1, 2]);
+ const fakeReportAction = LHNTestUtils.getFakeAdvancedReportAction();
+ const fakePolicy = LHNTestUtils.getFakePolicy(fakeReport.policyID);
+ const fakePersonalDetails = {
+ [fakeReportAction.actorAccountID]: {
+ accountID: fakeReportAction.actorAccountID,
+ login: 'email1@test.com',
+ displayName: 'Email One',
+ avatar: 'https://example.com/avatar.png',
+ firstName: 'One',
+ },
+ };
+
+ beforeEach(() => {
+ LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction);
+ });
+
+ function setup() {
+ return waitForBatchedUpdates().then(() =>
+ Onyx.multiSet({
+ [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails,
+ [ONYXKEYS.IS_LOADING_REPORT_DATA]: false,
+ [`${ONYXKEYS.COLLECTION.POLICY}${fakeReport.policyID}`]: fakePolicy,
+ }),
+ );
+ }
+
+ it('renders secondary Avatar properly', () => {
+ const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon';
+
+ return setup().then(() => {
+ expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeDefined();
+ });
+ });
+
+ it('renders Person information', () => {
+ const [expectedPerson] = fakeReportAction.person;
+
+ return setup().then(() => {
+ expect(screen.getByText(expectedPerson.text)).toBeDefined();
+ });
+ });
+ });
+ });
+});
diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js
index ce4edc75b444..6e7d4390b4e9 100644
--- a/tests/utils/LHNTestUtils.js
+++ b/tests/utils/LHNTestUtils.js
@@ -5,10 +5,13 @@ import ComposeProviders from '../../src/components/ComposeProviders';
import OnyxProvider from '../../src/components/OnyxProvider';
import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData';
+import ReportActionItemSingle from '../../src/pages/home/report/ReportActionItemSingle';
import {EnvironmentProvider} from '../../src/components/withEnvironment';
import {CurrentReportIDContextProvider} from '../../src/components/withCurrentReportID';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
+import reportPropTypes from '../../src/pages/reportPropTypes';
+import reportActionPropTypes from '../../src/pages/home/report/reportActionPropTypes';
// we have to mock `useIsFocused` because it's used in the SidebarLinks component
const mockedNavigate = jest.fn();
@@ -167,6 +170,63 @@ function getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorksp
};
}
+/**
+ * @param {Number[]} [participantAccountIDs]
+ * @param {Number} [millisecondsInThePast] the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages)
+ * @param {boolean} [isUnread]
+ * @returns {Object}
+ */
+function getFakeReportWithPolicy(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false) {
+ return {
+ ...getFakeReport(participantAccountIDs, millisecondsInThePast, isUnread),
+ type: CONST.REPORT.TYPE.CHAT,
+ chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
+ policyID: '08CE60F05A5D86E1',
+ oldPolicyName: '',
+ isOwnPolicyExpenseChat: false,
+ ownerAccountID: participantAccountIDs[0],
+ };
+}
+
+/**
+ * @param {Number} [id]
+ * @param {String} [name]
+ * @returns {Object}
+ */
+function getFakePolicy(id = 1, name = 'Workspace-Test-001') {
+ return {
+ id,
+ name,
+ isFromFullPolicy: false,
+ role: 'admin',
+ type: 'free',
+ owner: 'myuser@gmail.com',
+ outputCurrency: 'BRL',
+ avatar: '',
+ employeeList: [],
+ isPolicyExpenseChatEnabled: true,
+ areChatRoomsEnabled: true,
+ lastModified: 1697323926777105,
+ autoReporting: true,
+ autoReportingFrequency: 'immediate',
+ defaultBillable: false,
+ disabledFields: {defaultBillable: true, reimbursable: false},
+ };
+}
+
+/**
+ * @param {String} actionName
+ * @param {String} actor
+ * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages)
+ * @returns {Object}
+ */
+function getFakeAdvancedReportAction(actionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0) {
+ return {
+ ...getFakeReportAction(actor, millisecondsInThePast),
+ actionName,
+ };
+}
+
/**
* @param {String} [currentReportID]
*/
@@ -218,4 +278,97 @@ MockedSidebarLinks.defaultProps = {
currentReportID: '',
};
-export {fakePersonalDetails, getDefaultRenderedSidebarLinks, getAdvancedFakeReport, getFakeReport, getFakeReportAction, MockedSidebarLinks};
+/**
+ * @param {React.ReactElement} component
+ */
+function internalRender(component) {
+ // A try-catch block needs to be added to the rendering so that any errors that happen while the component
+ // renders are caught and logged to the console. Without the try-catch block, Jest might only report the error
+ // as "The above error occurred in your component", without providing specific details. By using a try-catch block,
+ // any errors are caught and logged, allowing you to identify the exact error that might be causing a rendering issue
+ // when developing tests.
+
+ try {
+ render(component);
+ } catch (error) {
+ console.error(error);
+ }
+}
+
+/**
+ * @param {Boolean} [shouldShowSubscriptAvatar]
+ * @param {Object} [report]
+ * @param {Object} [reportAction]
+ */
+function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report = null, reportAction = null) {
+ const currentReport = report || getFakeReport();
+ const currentReportAction = reportAction || getFakeAdvancedReportAction();
+
+ internalRender(
+ ,
+ );
+}
+
+/**
+ * @param {Boolean} shouldShowSubscriptAvatar
+ * @param {Object} report
+ * @param {Object} reportAction
+ * @returns {JSX.Element}
+ */
+function MockedReportActionItemSingle({shouldShowSubscriptAvatar, report, reportAction}) {
+ const personalDetailsList = {
+ [reportAction.actorAccountID]: {
+ accountID: reportAction.actorAccountID,
+ login: 'email1@test.com',
+ displayName: 'Email One',
+ avatar: 'https://example.com/avatar.png',
+ firstName: 'One',
+ },
+ };
+
+ return (
+
+
+
+ );
+}
+
+MockedReportActionItemSingle.propTypes = {
+ shouldShowSubscriptAvatar: PropTypes.bool,
+ report: reportPropTypes,
+ reportAction: PropTypes.shape(reportActionPropTypes),
+};
+
+MockedReportActionItemSingle.defaultProps = {
+ shouldShowSubscriptAvatar: true,
+ report: null,
+ reportAction: null,
+};
+
+export {
+ fakePersonalDetails,
+ getDefaultRenderedSidebarLinks,
+ getAdvancedFakeReport,
+ getFakeReport,
+ getFakeReportAction,
+ MockedSidebarLinks,
+ getDefaultRenderedReportActionItemSingle,
+ MockedReportActionItemSingle,
+ getFakeReportWithPolicy,
+ getFakePolicy,
+ getFakeAdvancedReportAction,
+};